python - 验证随时间变化的连续条件

标签 python multithreading time concurrency python-multithreading

我想开发一个Python程序,从某个时刻开始,等待60秒再执行操作。该程序必须具有的另一个功能是,如果我更新初始时间,它必须开始检查条件。我想过用线程来做,但我不知道如何停止线程并以新的开始时间重新启动它。

import thread
import time


# Define a function for the thread
def check_message (last, timer):
    oldtime = time.time()
    print oldtime
    # check
    while time.time() - oldtime <= 60:
    print (time.time() - oldtime)
    print "One minute"+ str(time.time())
    return 1

# Create two threads as follows
try:
    named_tuple = time.localtime() # get struct_time
    time_string = time.strftime("%H:%M:%S", named_tuple)
    thread.start_new_thread(check_message , (time_string, 60))
except:
    print "Error: unable to start thread"

while 1:
    pass

谢谢!

最佳答案

这里可能没有必要检查循环中的时间,而且很浪费,因为您可以将线程置于 sleep 状态,并在时间到了时让内核将其唤醒。 线程库提供threading.Timer对于此类用例。您的情况的困难在于,您无法中断这样的 sleep 线程来调整执行指定函数的时间间隔。

我在下面的示例中使用自定义管理器类 TimeLord 来克服此限制。 TimeLord 通过取消当前计时器并用新计时器替换它来“重置”计时器。 为此,TimeLord 包含一个包装中间工作函数和一个“ token ”属性,必须由正在运行的计时器实例弹出该属性才能执行指定的目标函数。

此设计保证指定目标函数的唯一执行,因为 dict.pop() 是原子操作。只要当前计时器尚未启动其线程并弹出 _tokentimelord.reset() 就有效。这种方法不能完全防止尝试“重置”时新计时器线程的潜在无效启动,但当发生这种情况时,它是一种不重要的冗余,因为目标函数只能执行一次。

此代码使用 Python 2 和 3 运行:

import time
from datetime import datetime
from threading import Timer, current_thread


def f(x):
    print('{} {}: RUNNING TARGET FUNCTION'.format(
        datetime.now(), current_thread().name)
    )
    time.sleep(x)
    print('{} {}: EXITING'.format(datetime.now(), current_thread().name))


class TimeLord:
    """
    Manager Class for threading.Timer instance. Allows "resetting" `interval`
    as long execution of `function` has not started by canceling the old
    and constructing a new timer instance.
    """
    def worker(self, *args, **kwargs):
        try:
            self.__dict__.pop("_token") # dict.pop() is atomic
        except KeyError:
            pass
        else:
            self.func(*args, **kwargs)

    def __init__(self, interval, function, args=None, kwargs=None):
        self.func = function
        self.args = args if args is not None else []
        self.kwargs = kwargs if kwargs is not None else {}
        self._token = True
        self._init_timer(interval)

    def _init_timer(self, interval):
        self._timer = Timer(interval, self.worker, self.args, self.kwargs)
        self._timer.daemon = True

    def start(self):
        self._timer.start()
        print('{} {}: STARTED with `interval={}`'.format(
            datetime.now(), self._timer.name, self._timer.interval)
        )

    def reset(self, interval):
        """Cancel latest timer and start a new one if `_token` is still there.
        """
        print('{} {}: CANCELED'.format(datetime.now(), self._timer.name))
        self._timer.cancel()

        # reduces, but doesn't prevent, occurrences when a new timer
        # gets created which eventually will not succeed in popping
        # the `_token`. That's uncritical redundancy when it happens.
        # Only one thread ever will be able to execute `self.func()`

        if hasattr(self, "_token"):
            self._init_timer(interval)
            self.start()

    def cancel(self):
        self._timer.cancel()

    def join(self, timeout=None):
        self._timer.join(timeout=timeout)

def run_demo(initial_interval):

    print("*** testing with initial interval {} ***".format(initial_interval))
    tl = TimeLord(interval=initial_interval, function=f, args=(10,))
    tl.start()

    print('*** {} sleeping two seconds ***'.format(datetime.now()))
    time.sleep(2)

    tl.reset(interval=6)
    tl.reset(interval=7)
    tl.join()
    print("-" * 70)


if __name__ == '__main__':

    run_demo(initial_interval=5)
    run_demo(initial_interval=2)

示例输出:

*** testing with initial interval 5 ***
2019-06-05 20:58:23.448404 Thread-1: STARTED with `interval=5`
*** 2019-06-05 20:58:23.448428 sleeping two seconds ***
2019-06-05 20:58:25.450483 Thread-1: CANCELED
2019-06-05 20:58:25.450899 Thread-2: STARTED with `interval=6`
2019-06-05 20:58:25.450955 Thread-2: CANCELED
2019-06-05 20:58:25.451496 Thread-3: STARTED with `interval=7`
2019-06-05 20:58:32.451592 Thread-3: RUNNING TARGET FUNCTION
2019-06-05 20:58:42.457527 Thread-3: EXITING
----------------------------------------------------------------------
*** testing with initial interval 2 ***
2019-06-05 20:58:42.457986 Thread-4: STARTED with `interval=2`
*** 2019-06-05 20:58:42.458033 sleeping two seconds ***
2019-06-05 20:58:44.458058 Thread-4: RUNNING TARGET FUNCTION
2019-06-05 20:58:44.459649 Thread-4: CANCELED
2019-06-05 20:58:44.459724 Thread-4: CANCELED
2019-06-05 20:58:54.466342 Thread-4: EXITING
----------------------------------------------------------------------

Process finished with exit code 0

注意,当interval=2时,两秒后的取消没有效果,因为计时器已经在执行目标函数。

关于python - 验证随时间变化的连续条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54494990/

相关文章:

c# - 为什么这个任务会提前返回?我做错了什么吗?

asp.net - ASP.NET开发人员真的需要关心线程安全吗?

java - 使用 Thread 和 Thread.sleep 更改周期性运动的间隔

c - 如何在 C 中使用 mktime 检查日期是否有效?

python - 返回在字典中的键上循环的第一个值条目的最大值

python - 将所有相同的值索引放入一行

python - Django-Filter 并使用数组进行查询

python - Pandas Dataframe 输出到 JSON

algorithm - 如何确定算法函数的复杂度?

c# - 在 Noda Time 中获取系统的 LocalDateTime