不止一次调用thread.timer()

时间:2014-03-16 02:23:58

标签: python multithreading

代码:

from threading import Timer
import time

def hello():
    print "hello"

a=Timer(3,hello,())
a.start()
time.sleep(4)
a.start()

运行此脚本后,我收到错误:RuntimeError: threads can only be started once 那么我该如何处理这个错误呢。我想不止一次启动计时器。

2 个答案:

答案 0 :(得分:4)

threading.Timer继承threading.Thread。线程对象不可重用。您可以为每个呼叫创建Timer个实例。

from threading import Timer
import time

class RepeatableTimer(object):
    def __init__(self, interval, function, args=[], kwargs={}):
        self._interval = interval
        self._function = function
        self._args = args
        self._kwargs = kwargs
    def start(self):
        t = Timer(self._interval, self._function, *self._args, **self._kwargs)
        t.start()

def hello():
    print "hello"

a=RepeatableTimer(3,hello,())
a.start()
time.sleep(4)
a.start()

答案 1 :(得分:0)

由于我每次烘烤cookie时都会启动烤箱定时器,因此我很惊讶地看到python的定时器只是一次性的。 也就是说,我共享一个小型计时器类,该类在 start 方法上提供了更多选项:

  • 返回自身以允许创建和启动单行计时器
  • 可选参数,用于在计时器仍处于活动状态时重新启动新计时器

实施:

from threading import Timer, Lock


class TimerEx(object):
    """
    A reusable thread safe timer implementation
    """

def __init__(self, interval_sec, function, *args, **kwargs):
    """
    Create a timer object which can be restarted

    :param interval_sec: The timer interval in seconds
    :param function: The user function timer should call once elapsed
    :param args: The user function arguments array (optional)
    :param kwargs: The user function named arguments (optional)
    """
    self._interval_sec = interval_sec
    self._function = function
    self._args = args
    self._kwargs = kwargs
    # Locking is needed since the '_timer' object might be replaced in a different thread
    self._timer_lock = Lock()
    self._timer = None

def start(self, restart_if_alive=True):
    """
    Starts the timer and returns this object [e.g. my_timer = TimerEx(10, my_func).start()]

    :param restart_if_alive: 'True' to start a new timer if current one is still alive
    :return: This timer object (i.e. self)
    """
    with self._timer_lock:
        # Current timer still running
        if self._timer is not None:
            if not restart_if_alive:
                # Keep the current timer
                return self
            # Cancel the current timer
            self._timer.cancel()
        # Create new timer
        self._timer = Timer(self._interval_sec, self.__internal_call)
        self._timer.start()
    # Return this object to allow single line timer start
    return self

def cancel(self):
    """
    Cancels the current timer if alive
    """
    with self._timer_lock:
        if self._timer is not None:
            self._timer.cancel()
            self._timer = None

def is_alive(self):
    """
    :return: True if current timer is alive (i.e not elapsed yet)
    """
    with self._timer_lock:
        if self._timer is not None:
            return self._timer.is_alive()
    return False

def __internal_call(self):
    # Release timer object
    with self._timer_lock:
        self._timer = None
    # Call the user defined function
    self._function(*self._args, **self._kwargs)

以下是一个示例:

from time import sleep

def my_func(msg):
    print(msg)

my_timer = TimerEx(interval_sec=5, function=my_func, msg="Here is my message").start()
sleep(10)
my_timer.start()
sleep(10)

注意::我使用的是python 3.7,所以我不确定100%可以在python 2上使用