I am working on Windows. I want to execute a function foo()
every 10 seconds.
How do I do this?
-
Looks like the standard library itself provides no baked function for that. You may want to look at event loop implementations. – matanster Jan 22 '22 at 18:06
-
[timed-count](https://pypi.org/project/timed-count/) is a good replacement for a loop that contains a call to `time.sleep`. It is precise, does not dependent on the loop execution time, and won't accumulate temporal drift. – 101 Dec 26 '22 at 12:06
9 Answers
At the end of foo()
, create a Timer
which calls foo()
itself after 10 seconds.
Because, Timer
create a new thread
to call foo()
.
You can do other stuff without being blocked.
import time, threading
def foo():
print(time.ctime())
threading.Timer(10, foo).start()
foo()
#output:
#Thu Dec 22 14:46:08 2011
#Thu Dec 22 14:46:18 2011
#Thu Dec 22 14:46:28 2011
#Thu Dec 22 14:46:38 2011
-
58One thing to watch out for here is start time "drift". I just ran a test and my times drifted by +0.05s in about 33 iterations. I was running 1 second polls, and this means a drift of 20% in less than a minute. You can _reduce_ drift by calling the `threading.Timer` at the start of the function rather than at the end, but only if it is function duration that is causing your drift, not timer unreliability. The best way to reduce drift is to only sleep for as long as require until the next expected run time. I'll add an example as another answer. – Michael Anderson Aug 12 '13 at 05:12
-
3this also has the overhead of instantiating a new object (in a new thread!) every single period. i couldn't find a really good solution to this problem but I've thought about it a bit and am posting an answer below shortly that uses a generator – watsonic Jan 19 '15 at 21:50
-
9What about memory usage here ? feel like a infinite recursive call, is it ? – Arun Mar 30 '17 at 05:06
-
1restart the timer first, then do your task (in this case print). This will minimise the time drift – SoloPilot Feb 07 '18 at 17:35
-
1
-
3This solution is kind of brittle. Any uncaught exception (e. g. `IOError`) raised by the payload (`print` in this case) will lead to a termination of the complete schedule. I'd prefer a solution which would handle such things more gracefully and recover to the original behavior once the reason for the exception (e. g. a full disk) is fixed. – Alfe Apr 12 '18 at 15:39
-
-
2How would you kill the timer threads as they continue to grow in numbers? – Moondra Apr 17 '19 at 22:11
-
-
If you‘re going to be starting the timer immediately before thread exits, how is this any better than just looping and sleeping 10 seconds within the same worker thread? It seems to spawn off an unlimited number of threads for no good reason, when just one worker thread would have sufficed. – wim Oct 15 '20 at 18:04
Simply sleeping for 10 seconds or using threading.Timer(10,foo)
will result in start time drift. (You may not care about this, or it may be a significant source of problems depending on your exact situation.) There can be two causes for this - inaccuracies in the wake up time of your thread or execution time for your function.
You can see some results at the end of this post, but first an example of how to fix it. You need to track when your function should next be called as opposed to when it actually got called and account for the difference.
Here's a version that drifts slightly:
import datetime, threading
def foo():
print datetime.datetime.now()
threading.Timer(1, foo).start()
foo()
Its output looks like this:
2013-08-12 13:05:36.483580
2013-08-12 13:05:37.484931
2013-08-12 13:05:38.485505
2013-08-12 13:05:39.486945
2013-08-12 13:05:40.488386
2013-08-12 13:05:41.489819
2013-08-12 13:05:42.491202
2013-08-12 13:05:43.492486
2013-08-12 13:05:44.493865
2013-08-12 13:05:45.494987
2013-08-12 13:05:46.496479
2013-08-12 13:05:47.497824
2013-08-12 13:05:48.499286
2013-08-12 13:05:49.500232
You can see that the sub-second count is constantly increasing and thus, the start time is "drifting".
This is code that correctly accounts for drift:
import datetime, threading, time
next_call = time.time()
def foo():
global next_call
print datetime.datetime.now()
next_call = next_call+1
threading.Timer( next_call - time.time(), foo ).start()
foo()
Its output looks like this:
2013-08-12 13:21:45.292565
2013-08-12 13:21:47.293000
2013-08-12 13:21:48.293939
2013-08-12 13:21:49.293327
2013-08-12 13:21:50.293883
2013-08-12 13:21:51.293070
2013-08-12 13:21:52.293393
Here you can see that there is no longer any increase in the sub-second times.
If your events are occurring really frequently you may want to run the timer in a single thread, rather than starting a new thread for each event. While accounting for drift this would look like:
import datetime, threading, time
def foo():
next_call = time.time()
while True:
print datetime.datetime.now()
next_call = next_call+1;
time.sleep(next_call - time.time())
timerThread = threading.Thread(target=foo)
timerThread.start()
However your application will not exit normally, you'll need to kill the timer thread. If you want to exit normally when your application is done, without manually killing the thread, you should use
timerThread = threading.Thread(target=foo)
timerThread.daemon = True
timerThread.start()

- 70,661
- 7
- 134
- 187
-
7it seems wasteful to create a thread for each call. [You could do it in a single thread](http://stackoverflow.com/a/20169930/4279) – jfs Oct 28 '14 at 13:59
-
@J.F.Sebastian agreed, this was primarily implemented as an extension to the top voted answer. The thread overhead is usually pretty small, but if your actions are frequent you need to do something different - running the action as a single thread is a trivial (but often important) extension, some systems also use dedicated data structures so that many events can be scheduled on a single thread (which is not so trivial). – Michael Anderson Oct 29 '14 at 00:28
-
+1, LGTM. If you want [to stop calling the function before the process exits, you could use `threading.Event()`](http://stackoverflow.com/a/22498708/4279). – jfs Oct 29 '14 at 08:38
-
what if the work to do takes longer than the interval's length? How would you handle it? – KiaMorot Nov 29 '16 at 08:20
-
2@KiaMorot There's not really a good solution in the case where work is taking longer it takes to process it. In this case, use `max(0, next_call - time.time())` as the argument to sleep, then you will at least be restarting immediately. – Michael Anderson Nov 29 '16 at 09:01
-
1@MichaelAnderson How we can use those wait seconds for other work? – Bimlesh Sharma Jun 29 '17 at 17:55
Surprised to not find a solution using a generator for timing. I just designed this one for my own purposes.
This solution: single threaded, no object instantiation each period, uses generator for times, rock solid on timing down to precision of the time
module (unlike several of the solutions I've tried from stack exchange).
Note: for Python 2.x, replace next(g)
below with g.next()
.
import time
def do_every(period,f,*args):
def g_tick():
t = time.time()
while True:
t += period
yield max(t - time.time(),0)
g = g_tick()
while True:
time.sleep(next(g))
f(*args)
def hello(s):
print('hello {} ({:.4f})'.format(s,time.time()))
time.sleep(.3)
do_every(1,hello,'foo')
Results in, for example:
hello foo (1421705487.5811)
hello foo (1421705488.5811)
hello foo (1421705489.5809)
hello foo (1421705490.5830)
hello foo (1421705491.5803)
hello foo (1421705492.5808)
hello foo (1421705493.5811)
hello foo (1421705494.5811)
hello foo (1421705495.5810)
hello foo (1421705496.5811)
hello foo (1421705497.5810)
hello foo (1421705498.5810)
hello foo (1421705499.5809)
hello foo (1421705500.5811)
hello foo (1421705501.5811)
hello foo (1421705502.5811)
hello foo (1421705503.5810)
Note that this example includes a simulation of the cpu doing something else for .3 seconds each period. If you changed it to be random each time it wouldn't matter. The max in the yield
line serves to protect sleep
from negative numbers in case the function being called takes longer than the period specified. In that case it would execute immediately and make up the lost time in the timing of the next execution.

- 3,155
- 1
- 27
- 31
-
3Under Python 3.x, time.sleep(g.next()) doesn't work. Switching to time.sleep(next(g)) does the trick. – goobering Jan 07 '16 at 12:23
-
-
Extremely neat! Especially the fact that it doesn't drift. If before `f(*args)` you add `if f is None: yield else:` you can use the code in a loop, like `for _ in do_every(1, None): print('hello foo ({:.4f})'.format(s,time.time()))` – Makers_F Jan 20 '16 at 10:39
-
2Am trying to take exact samples of real world measurements on a Pi. Am old signal processing veteran. This is the correct solution. – Paul S Dec 13 '17 at 06:06
-
@watsonic, you made my day.....really, I was hardly stuck for all day, then I applied your trick and bingoooo.... THAKSATONNNNNN..... greatttt – Viraj Mohite Dec 05 '18 at 05:18
-
-
1
-
2So elegant that I'm surprised there are no built-ins providing this behavior. Thanks for sharing! – bsplosion Feb 13 '20 at 17:56
-
1You can simplify the code like this to eliminate the count variable `def do_every(period,f,*args): def g_tick(): t = time.time() while True: t += period yield max(t - time.time(),0) g = g_tick() while True: time.sleep(next(g)) f(*args)` – Tim Dowty Jul 15 '20 at 16:58
-
-
-
-
This is the only answer among hundreds I've seen that accounts for drift. Bravo! This should be in the standard library. – Iain Samuel McLean Elder Feb 05 '22 at 15:08
Perhaps the sched module will meet your needs.
Alternatively, consider using a Timer object.

- 216,523
- 63
- 388
- 485
-
1sched module is the most flexible of the ways this can be done. Thanks for the link. – Harish Ganesan Mar 07 '21 at 21:06
-
Could you provide example code? I want to believe the Python standard library solves this problem, but the docs for sched don't show how. How do you implement a precise timer using sched? – Iain Samuel McLean Elder Feb 05 '22 at 15:11
This will insert a 10 second sleep in between every call to foo()
, which is approximately what you asked for should the call complete quickly.
import time
while True:
foo()
time.sleep(10)
To do other things while your foo()
is being called in a background thread
import time
import sys
import threading
def foo():
sys.stdout.write('({}) foo\n'.format(time.ctime()))
def foo_target():
while True:
foo()
time.sleep(10)
t = threading.Thread(target=foo_target)
t.daemon = True
t.start()
print('doing other things...')

- 338,267
- 99
- 616
- 750
-
I want to do other stuff too while waiting. Is there some way to use signals? – Bruce Dec 22 '11 at 06:35
-
If your `foo()` takes an unknown amount of time to finish, you would want to spawn a thread to execute a `foo()` every 10 seconds, I can show you how to that if necessary. – wim Dec 22 '11 at 06:36
-
-
Here's a nice implementation using the Thread class: http://g-off.net/software/a-python-repeatable-threadingtimer-class
the code below is a little more quick and dirty:
from threading import Timer
from time import sleep
def hello():
print "hello, world"
t = Timer(3,hello)
t.start()
t = Timer(3, hello)
t.start() # after 3 seconds, "hello, world" will be printed
# timer will wake up ever 3 seconds, while we do something else
while True:
print "do something else"
sleep(10)

- 3,163
- 23
- 19
Here's a simple single threaded sleep based version that drifts, but tries to auto-correct when it detects drift.
NOTE: This will only work if the following 3 reasonable assumptions are met:
- The time period is much larger than the execution time of the function being executed
- The function being executed takes approximately the same amount of time on each call
- The amount of drift between calls is less than a second
-
from datetime import timedelta
from datetime import datetime
def exec_every_n_seconds(n,f):
first_called=datetime.now()
f()
num_calls=1
drift=timedelta()
time_period=timedelta(seconds=n)
while 1:
time.sleep(n-drift.microseconds/1000000.0)
current_time = datetime.now()
f()
num_calls += 1
difference = current_time - first_called
drift = difference - time_period* num_calls
print "drift=",drift

- 43,122
- 10
- 80
- 104
-
1+1 for a single-threaded version that compensates for drift. [Here're couple of similar code examples](https://gist.github.com/zed/9cb41b2cfe615a7be3e9) – jfs Oct 28 '14 at 13:58
-
Note that `num_calls` should be initialized to `0`, not `1`, otherwise you will get an exception in `time.sleep` because its parameter can become negative. – HRJ Jul 18 '17 at 06:28
-
This will block the execution of the rest of the code from where the function `exec_every_n_seconds()` is called. How to handle this situation without using more than one thread? – hafiz031 Feb 14 '22 at 01:25
You can execute your task in a different thread. threading.Timer
will let you execute a given callback once after some time has elapsed, if you want to execute your task, for example, as long as the callback returns True
(this is actually what glib.timeout_add
provides, but you might not have it installed in windows) or until you cancel it, you can use this code:
import logging, threading, functools
import time
logging.basicConfig(level=logging.NOTSET,
format='%(threadName)s %(message)s')
class PeriodicTimer(object):
def __init__(self, interval, callback):
self.interval = interval
@functools.wraps(callback)
def wrapper(*args, **kwargs):
result = callback(*args, **kwargs)
if result:
self.thread = threading.Timer(self.interval,
self.callback)
self.thread.start()
self.callback = wrapper
def start(self):
self.thread = threading.Timer(self.interval, self.callback)
self.thread.start()
def cancel(self):
self.thread.cancel()
def foo():
logging.info('Doing some work...')
return True
timer = PeriodicTimer(1, foo)
timer.start()
for i in range(2):
time.sleep(2)
logging.info('Doing some other work...')
timer.cancel()
Example output:
Thread-1 Doing some work...
Thread-2 Doing some work...
MainThread Doing some other work...
Thread-3 Doing some work...
Thread-4 Doing some work...
MainThread Doing some other work...
Note: The callback isn't executed every interval execution. Interval is the time the thread waits between the callback finished the last time and the next time is called.

- 39,419
- 8
- 102
- 133
If you meant to run foo() inside a python script every 10 seconds, you can do something on these lines.
import time
def foo():
print "Howdy"
while True:
foo()
time.sleep(10)

- 4,038
- 21
- 46