RepeatedTimer now allows adaptive interval and dynamic loop condition
This commit is contained in:
parent
18dd1659da
commit
50862668b1
1 changed files with 53 additions and 9 deletions
|
|
@ -536,7 +536,7 @@ def address_for_client(host, port):
|
|||
|
||||
class RepeatedTimer(threading.Thread):
|
||||
"""
|
||||
This class represents an action that should be run repeatedly in a predefined interval. It is similar to python's
|
||||
This class represents an action that should be run repeatedly in an interval. It is similar to python's
|
||||
own :class:`threading.Timer` class, but instead of only running once the ``function`` will be run again and again,
|
||||
sleeping the stated ``interval`` in between.
|
||||
|
||||
|
|
@ -554,48 +554,92 @@ class RepeatedTimer(threading.Thread):
|
|||
t = RepeatedTimer(1.0, hello)
|
||||
t.start() # prints "Hello World!" every second
|
||||
|
||||
Another example with dynamic interval and loop condition:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
count = 0
|
||||
maximum = 5
|
||||
factor = 1
|
||||
|
||||
def interval():
|
||||
global count
|
||||
global factor
|
||||
return count * factor
|
||||
|
||||
def condition():
|
||||
global count
|
||||
global maximum
|
||||
return count <= maximum
|
||||
|
||||
def hello():
|
||||
print("Hello World!")
|
||||
|
||||
global count
|
||||
count += 1
|
||||
|
||||
t = RepeatedTimer(interval, hello, run_first=True, condition=condition)
|
||||
t.start() # prints "Hello World!" 5 times, printing the first one
|
||||
# directly, then waiting 1, 2, 3, 4s in between (adaptive interval)
|
||||
|
||||
Arguments:
|
||||
interval (float): The interval between each ``function`` call, in seconds.
|
||||
interval (float or callable): The interval between each ``function`` call, in seconds. Can also be a callable
|
||||
returning the interval to use, in case the interval is not static.
|
||||
function (callable): The function to call.
|
||||
args (list or tuple): The arguments for the ``function`` call.
|
||||
kwargs (dict): The keyword arguments for the ``function`` call.
|
||||
args (list or tuple): The arguments for the ``function`` call. Defaults to an empty list.
|
||||
kwargs (dict): The keyword arguments for the ``function`` call. Defaults to an empty dict.
|
||||
run_first (boolean): If set to True, the function will be run for the first time *before* the first wait period.
|
||||
If set to False (the default), the function will be run for the first time *after* the first wait period.
|
||||
condition (callable): Condition that needs to be True for loop to continue. Defaults to ``lambda: True``.
|
||||
"""
|
||||
|
||||
def __init__(self, interval, function, args=None, kwargs=None, run_first=False):
|
||||
def __init__(self, interval, function, args=None, kwargs=None, run_first=False, condition=None):
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
if args is None:
|
||||
args = []
|
||||
if kwargs is None:
|
||||
kwargs = dict()
|
||||
if condition is None:
|
||||
condition = lambda: True
|
||||
|
||||
if not callable(interval):
|
||||
self.interval = lambda: interval
|
||||
else:
|
||||
self.interval = interval
|
||||
|
||||
self.interval = interval
|
||||
self.function = function
|
||||
self.finished = threading.Event()
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.run_first = run_first
|
||||
self.condition = condition
|
||||
|
||||
def cancel(self):
|
||||
self.finished.set()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
while self.condition():
|
||||
if self.run_first:
|
||||
# if we are to run the function BEFORE waiting for the first time
|
||||
self.function(*self.args, **self.kwargs)
|
||||
|
||||
# make sure our condition is still met before running into the downtime
|
||||
if not self.condition():
|
||||
break
|
||||
|
||||
# wait, but break if we are cancelled
|
||||
self.finished.wait(self.interval)
|
||||
self.finished.wait(self.interval())
|
||||
if self.finished.is_set():
|
||||
return
|
||||
break
|
||||
|
||||
if not self.run_first:
|
||||
# if we are to run the function AFTER waiting for the first time
|
||||
self.function(*self.args, **self.kwargs)
|
||||
|
||||
# make sure we set our finished event so we can detect that the loop was finished
|
||||
self.finished.set()
|
||||
|
||||
|
||||
class CountedEvent(object):
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue