Skip to content

Instantly share code, notes, and snippets.

@cypreess
Last active February 28, 2024 02:59
Show Gist options
  • Save cypreess/5481681 to your computer and use it in GitHub Desktop.
Save cypreess/5481681 to your computer and use it in GitHub Desktop.
Python periodic thread using timer. You can cancel this thread any time. Thread will live at maximum to the end of one single processing run, otherwise it will end in the same time (especially during a wait time for next run). This code avoids the problem of waiting very long for thread exiting, because it does not uses time.sleep(). Please be a…
import logging
import threading
class PeriodicThread(object):
"""
Python periodic Thread using Timer with instant cancellation
"""
def __init__(self, callback=None, period=1, name=None, *args, **kwargs):
self.name = name
self.args = args
self.kwargs = kwargs
self.callback = callback
self.period = period
self.stop = False
self.current_timer = None
self.schedule_lock = threading.Lock()
def start(self):
"""
Mimics Thread standard start method
"""
self.schedule_timer()
def run(self):
"""
By default run callback. Override it if you want to use inheritance
"""
if self.callback is not None:
self.callback()
def _run(self):
"""
Run desired callback and then reschedule Timer (if thread is not stopped)
"""
try:
self.run()
except Exception, e:
logging.exception("Exception in running periodic thread")
finally:
with self.schedule_lock:
if not self.stop:
self.schedule_timer()
def schedule_timer(self):
"""
Schedules next Timer run
"""
self.current_timer = threading.Timer(self.period, self._run, *self.args, **self.kwargs)
if self.name:
self.current_timer.name = self.name
self.current_timer.start()
def cancel(self):
"""
Mimics Timer standard cancel method
"""
with self.schedule_lock:
self.stop = True
if self.current_timer is not None:
self.current_timer.cancel()
def join(self):
"""
Mimics Thread standard join method
"""
self.current_timer.join()
@fkilleen
Copy link

Thanks for the code snippet.
However, line 31 should be self.callback(*self.args, **self.kwargs)

@vdbpeter
Copy link

vdbpeter commented Mar 4, 2020

Thanks! Works a treat. Was struggling to achieve this functionality with the fundamental threading.Timer, then stumbled across your work.

@midiwidi
Copy link

There should also be a self.stop = False just before line 24 so that the timer can get restarted after it was stopped with cancel().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment