What is the best way to repeatedly execute a function every x seconds? [closed]
If your program doesn't have a event loop already, use the sched module, which implements a general purpose event scheduler.
import sched, times = sched.scheduler(time.time, time.sleep)def do_something(sc): print("Doing stuff...") # do your stuff s.enter(60, 1, do_something, (sc,))s.enter(60, 1, do_something, (s,))s.run()
If you're already using an event loop library like asyncio
, trio
, tkinter
, PyQt5
, gobject
, kivy
, and many others - just schedule the task using your existing event loop library's methods, instead.
If you want a non-blocking way to execute your function periodically, instead of a blocking infinite loop I'd use a threaded timer. This way your code can keep running and perform other tasks and still have your function called every n seconds. I use this technique a lot for printing progress info on long, CPU/Disk/Network intensive tasks.
Here's the code I've posted in a similar question, with start() and stop() control:
from threading import Timerclass RepeatedTimer(object): def __init__(self, interval, function, *args, **kwargs): self._timer = None self.interval = interval self.function = function self.args = args self.kwargs = kwargs self.is_running = False self.start() def _run(self): self.is_running = False self.start() self.function(*self.args, **self.kwargs) def start(self): if not self.is_running: self._timer = Timer(self.interval, self._run) self._timer.start() self.is_running = True def stop(self): self._timer.cancel() self.is_running = False
Usage:
from time import sleepdef hello(name): print "Hello %s!" % nameprint "starting..."rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()try: sleep(5) # your long-running job goes here...finally: rt.stop() # better in a try/finally block to make sure the program ends!
Features:
- Standard library only, no external dependencies
start()
andstop()
are safe to call multiple times even if the timer has already started/stopped- function to be called can have positional and named arguments
- You can change
interval
anytime, it will be effective after next run. Same forargs
,kwargs
and evenfunction
!