I want to know how python threading.Timer works.
In more detail, When i run a couple of threading.Timer, does it run separate thread for counting a time and running the handler ?
Or one thread manages and counts a couple of timer together ?
I am asking because my application need to schedule many event, But
If threading.Timer runs separate each thread for counting a timer, and i run many timers, it may affect performance so much.
So i am worry that if i have to implement a scheduler running only one thread if it has big effect in performance.
threading.Timer class is a subclass of threading.Thread and basically it just runs a separate thread in which it sleeps for the specified amount of time and runs the corresponding function.
It is definitely not an efficient way to schedule events. Better way is to do the scheduling in a single thread by using Queue.PriorityQueue in which you would put your events where "priority" actually means "next fire date". Similar to how cron works.
Or even better: use something that already exists, do not reinvent the wheel: Cron, Celery, whatever...
A very simplified example of making a scheduler via Queue.PriorityQueue:
import time
from Queue import PriorityQueue
class Task(object):
def __init__(self, fn, crontab):
# TODO: it should be possible to pass args, kwargs
# so that fn can be called with fn(*args, **kwargs)
self.fn = fn
self.crontab = crontab
def get_next_fire_date(self):
# TODO: evaluate next fire date based on self.crontab
pass
class Scheduler(object):
def __init__(self):
self.event_queue = PriorityQueue()
self.new_task = False
def schedule_task(self, fn, crontab):
# TODO: add scheduling language, crontab or something
task = Task(fn, crontab)
next_fire = task.get_next_fire_date()
if next_fire:
self.new_task = True
self.event_queue.put((next_fire, task))
def run(self):
self.new_task = False
# TODO: do we really want an infinite loop?
while True:
# TODO: actually we want .get() with timeout and to handle
# the case when the queue is empty
next_fire, task = self.event_queue.get()
# incremental sleep so that we can check
# if new tasks arrived in the meantime
sleep_for = int(next_fire - time.time())
for _ in xrange(sleep_for):
time.sleep(1)
if self.new_task:
self.new_task = False
self.event_queue.put((next_fire, task))
continue
# TODO: run in separate thread?
task.fn()
time.sleep(1)
next_fire = task.get_next_fire_date()
if next_fire:
event_queue.put((next_fire, task))
def test():
return 'hello world'
sch = Scheduler()
sch.schedule_task(test, '5 * * * *')
sch.schedule_task(test, '0 22 * * 1-5')
sch.schedule_task(test, '1 1 * * *')
sch.run()
It's just an idea. You would have to properly implement both Task and Scheduler classes, i.e. get_next_fire_date method plus some kind of scheduling language (crontab?) and error handling. I still strongly suggest to use one of the existing libraries.
From the CPython 2.7 source:
def Timer(*args, **kwargs):
"""Factory function to create a Timer object.
Timers call a function after a specified number of seconds:
t = Timer(30.0, f, args=[], kwargs={})
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
return _Timer(*args, **kwargs)
class _Timer(Thread):
"""Call a function after a specified number of seconds:
t = Timer(30.0, f, args=[], kwargs={})
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
def __init__(self, interval, function, args=[], kwargs={}):
Thread.__init__(self)
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.finished = Event()
def cancel(self):
"""Stop the timer if it hasn't finished yet"""
self.finished.set()
def run(self):
self.finished.wait(self.interval)
if not self.finished.is_set():
self.function(*self.args, **self.kwargs)
self.finished.set()
As said in another answer, it is a separate thread (since it subclasses Thread). The callback function when the timer runs out is called from the new thread.
Related
I'm using the threading.Timer package to execute a method after x seconds. However, in some cases I want to execute this method earlier and cancel the timer (so it isn't called twice). How do I unit test this?
I want to know if the timer has stopped so that the method is not called anymore. I am now using the following code, unfortunately the is_alive still returns True
from threading import Timer
Class X():
def __init__(self, timeout):
self.timer = Timer(timeout, self.some_method)
self.timer.start()
def some_method(self):
# Do something
def other_method(self):
self.timer.cancel()
self.some_method()
import unittest
Class TestX(unittest.TestCase):
def test_cancel_timer(self):
x = X(1000)
x.other_method()
self.assertFalse(x.timer.is_alive())
Form the documentation the is_alive method returns True during the run operation;
Return whether the thread is alive.
This method returns True just before the run() method starts until just after the run() method terminates. The module function enumerate() returns a list of all alive threads.
The documentation on the cancel method says the following;
Stop the timer, and cancel the execution of the timer’s action. This will only work if the timer is still in its waiting stage.
Does this mean that the cancel method does not stop the run action? Or is is still in the grey area after the run method and returns True for that reason?
With timer.is_alive() you are just checking if the timer-thread itself is alive, so if you want to "check if timer.cancel() was called", you're testing for the wrong thing.
Does this mean that the cancel method does not stop the run action?
It does not stop the run()-function, right. timer.cancel() just sets a flag in an Event-object which gets checked by run. You can test if the flag is set with:
self.assertTrue(x.timer.finished.is_set())
Unfortunately, checking for cancellation is not enough to prevent repeated execution, since run can have already crossed the check like you can see in the source code:
# threading.py (Python 3.7.1):
class Timer(Thread):
"""Call a function after a specified number of seconds:
t = Timer(30.0, f, args=None, kwargs=None)
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
def __init__(self, interval, function, args=None, kwargs=None):
Thread.__init__(self)
self.interval = interval
self.function = function
self.args = args if args is not None else []
self.kwargs = kwargs if kwargs is not None else {}
self.finished = Event()
def cancel(self):
"""Stop the timer if it hasn't finished yet."""
self.finished.set()
def run(self):
self.finished.wait(self.interval)
if not self.finished.is_set():
self.function(*self.args, **self.kwargs)
self.finished.set()
Some more effort is needed to ensure unique execution. I've written up a possible solution to this in my answer here.
I need to pause and resume thread, which continuously executes some task. Execution begins when start() is called, it should not be interrupted and must continue from the point when pause() is called.
How can I do this?
Please remember that using threads in Python will not grant you a parallel processing, except for the case of IO blocking operations. For more information on this, take a look at this and this
You cannot pause a Thread arbitrarily in Python (please keep that in mind before reading further). I am neither sure you have a way to do that at an OS level (e.g. by using pure-C). What you can do is allow the thread to be paused at specific points you consider beforehand. I will give you an example:
class MyThread(threading.Thread):
def __init__(self, *args, **kwargs):
super(MyThread, self).__init__(*args, **kwargs)
self._event = threading.Event()
def run(self):
while True:
self.foo() # please, implement this.
self._event.wait()
self.bar() # please, implement this.
self._event.wait()
self.baz() # please, implement this.
self._event.wait()
def pause(self):
self._event.clear()
def resume(self):
self._event.set()
This approach will work but:
Threading is usually a bad idea, based on the links I gave you.
You have to code the run method by yourself, with this approach. This is because you need to have control over the exact points you'd like to check for pause, and this implies accessing the Thread object (perhaps you'd like to create an additional method instead of calling self._event.wait()).
The former point makes clear that you cannot pause arbitrarily, but just when you specified you could pause. Avoid having long operations between pause points.
Edit I did not test this one, but perhaps this will work without so much subclassing if you need more than one thread like this:
class MyPausableThread(threading.Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
self._event = threading.Event()
if target:
args = (self,) + args
super(MyPausableThread, self).__init__(group, target, name, args, kwargs)
def pause(self):
self._event.clear()
def resume(self):
self._event.set()
def _wait_if_paused(self):
self._event.wait()
This should allow you to create a custom thread without more subclassing, by calling MyPausableThread(target=myfunc).start(), and your callable's first parameter will receive the thread object, from which you can call self._wait_if_paused() when you need to pause-check.
Or even better, if you want to isolate the target from accessing the thread object:
class MyPausableThread(threading.Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
self._event = threading.Event()
if target:
args = ((lambda: self._event.wait()),) + args
super(MyPausableThread, self).__init__(group, target, name, args, kwargs)
def pause(self):
self._event.clear()
def resume(self):
self._event.set()
And your target callable will receive in the first parameter a function that can be called like this: pause_checker() (provided the first param in the target callable is named pause_checker).
You can do this by attaching a trace function that causes all other threads to wait for a signal:
import sys
import threading
import contextlib
# needed to enable tracing
if not sys.gettrace():
sys.settrace(lambda *args: None)
def _thread_frames(thread):
for thread_id, frame in sys._current_frames().items():
if thread_id == thread.ident:
break
else:
raise ValueError("No thread found")
# walk up to the root
while frame:
yield frame
frame = frame.f_back
#contextlib.contextmanager
def thread_paused(thread):
""" Context manager that pauses a thread for its duration """
# signal for the thread to wait on
e = threading.Event()
for frame in _thread_frames(thread):
# attach a new temporary trace handler that pauses the thread
def new(frame, event, arg, old = frame.f_trace):
e.wait()
# call the old one, to keep debuggers working
if old is not None:
return old(frame, event, arg)
frame.f_trace = new
try:
yield
finally:
# wake the other thread
e.set()
Which you can use as:
import time
def run_after_delay(func, delay):
""" Simple helper spawning a thread that runs a function in the future """
def wrapped():
time.sleep(delay)
func()
threading.Thread(target=wrapped).start()
main_thread = threading.current_thread()
def interrupt():
with thread_paused(main_thread):
print("interrupting")
time.sleep(2)
print("done")
run_after_delay(interrupt, 1)
start = time.time()
def actual_time(): return time.time() - start
print("{:.1f} == {:.1f}".format(0.0, actual_time()))
time.sleep(0.5)
print("{:.1f} == {:.1f}".format(0.5, actual_time()))
time.sleep(2)
print("{:.1f} != {:.1f}".format(2.5, actual_time()))
Giving
0.0 0.0
0.5 0.5
interrupting
done
2.5 3.0
Note how the interrupt causes the sleep on the main thread to wait longer
You can do this using Process class from psutil library.
Example:
>>> import psutil
>>> pid = 7012
>>> p = psutil.Process(pid)
>>> p.suspend()
>>> p.resume()
See this answer: https://stackoverflow.com/a/14053933
Edit: This method will suspend the whole process, not only one thread. ( I don't delete this answer, so others can know this method won't work.)
while(int(any) < 2000):
sleep(20)
print(waiting any...)
when I call a function with threading.Timer like below:
threading.Timer(LOOP_TIME,self.broadCast).start()
does broadCast get run in a separate thread? Or is it just in the same thread?
I'm using threading.Timer so I can have a function called every so much time interval. I do not want the broadCast function to be called outside of the main thread.
Yes. You can look into Python threading.py source code:
def Timer(*args, **kwargs):
"""Factory function to create a Timer object.
Timers call a function after a specified number of seconds:
t = Timer(30.0, f, args=[], kwargs={})
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
return _Timer(*args, **kwargs)
class _Timer(Thread):
"""Call a function after a specified number of seconds:
t = Timer(30.0, f, args=[], kwargs={})
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
def __init__(self, interval, function, args=[], kwargs={}):
Thread.__init__(self)
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.finished = Event()
Source code available in Python source code repository.
If you want timers and your main thread is not doing co-operative multitasking, I suggest you refactor your code so that you can use it from other threads.
i have a question about Timer object in Python:
https://docs.python.org/2/library/threading.html#timer-objects
This object is basically a Thread that calls a specific function after an amount of user defined seconds. My question is: after the function call, the Thread object is automatically eliminated of the program, or this object keeps running, consuming memory?
This snippet of code shows what i'm talking about:
from threading import Timer
from random import randint
def call_function(x):
print "Timer number " + str(x) + " hit call function!"
for x in range(200000):
#memory used: 700.000 K
print "Creating timer number: " + str(x)
Timer(randint(1, 10), call_function, [x]).start()
After 200.000 threads Timer created and being called in a space of 10 seconds (after this call they were supposed to be dead, releasing space, right?), the program end it's execution with 700.000 K of memory consumption, almost 1 GB.
Thanks,
Timer is just a Thread subclass (created by factory function named Timer) with simple run method:
class _Timer(Thread):
def __init__(self, interval, function, args=[], kwargs={}):
Thread.__init__(self)
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.finished = Event()
def cancel(self):
self.finished.set()
def run(self):
self.finished.wait(self.interval)
if not self.finished.is_set():
self.function(*self.args, **self.kwargs)
self.finished.set()
thread terminates just after the run() method terminates:
Once the thread’s activity is started, the thread is considered
‘alive’. It stops being alive when its run() method terminates –
either normally, or by raising an unhandled exception. The is_alive()
method tests whether the thread is alive.
timer class object itself should be garbage collected automatically if it will not be used later.
And you cant start 200000 threads, its too much (_Timer object will be created but thread will not start). Check this question: How many threads is too many?
Using the Timer class and restarting the timer in the callable, is the standard method of running a periodic timer in the background in python.
This has two major drawbacks:
it is not really periodic: setup of the timer, ...
it creates a new thread for each period
Is there an alternative to the Timer class? I have taken a look at the sched class, but running in the MainThread will block it, and it is not recommended to run it in a multithreaded environment.
How can I have a high frequency periodic timer (100 ms period) in python, for example to regularly empty a document queue when collecting bulk data to send to a database?
I have come up with the following alternative:
import threading
import time
class PeriodicThread(StoppableThread):
'''Similar to a Timer(), but uses only one thread, stops cleanly and exits when the main thread exits'''
def __init__ (self, period, callable, *args, **kwargs):
super(PeriodicThread, self).__init__()
self.period = period
self.args = args
self.callable = callable
self.kwargs = kwargs
self.daemon = True
def run(self):
while not self.stopped():
self.callable(*self.args, **self.kwargs)
time.sleep(self.period)