Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

timer interrupt thread python

I've been trying to make a precise timer in python, or as precise a OS allows it to be. But It seems to be more complicated than I initially thought.

This is how I would like it to work:

from time import sleep
from threading import Timer

def do_this():
    print ("hello, world")


t = Timer(4, do_this)
t.start()
sleep(20)
t.cancel()

Where during 20 seconds I would execute 'do_this' every fourth second. However 'do_this' executes once then the script terminates after 20 seconds.

Another way would be to create a thread with a while loop.

import time
import threading
import datetime

shutdown_event = threading.Event()

def dowork():
    while not shutdown_event.is_set():
        print(datetime.datetime.now())
        time.sleep(1.0)

def main():

    t = threading.Thread(target=dowork, args=(), name='worker')
    t.start()

    print("Instance started")

    try:
        while t.isAlive():
            t.join(timeout=1.0)
    except (KeyboardInterrupt, SystemExit):
            shutdown_event.set()
    pass

if __name__ == '__main__':
    main()

This thread executes as expected but I get a timing drift. In this case have to compensate for the time it takes to execute the code in the while loop by adjusting the sleep accordingly.

Is there a simple way in python to execute a timer every second (or any interval) without introducing a drift compared to the system time without having to compensate the sleep(n) parameter?

Thanks for helping,

/Anders

like image 410
Anders Cedronius Avatar asked Feb 07 '26 00:02

Anders Cedronius


1 Answers

If dowork() always runs in less time than your intervals, you can spawn a new thread every 4 seconds in a loop:

def dowork():
  wlen = random.random()
  sleep(wlen) # Emulate doing some work
  print 'work done in %0.2f seconds' % wlen

def main():
  while 1:
    t = threading.Thread(target=dowork)
    time.sleep(4)

If dowork() could potentially run for more than 4 seconds, then in your main loop you want to make sure the previous job is finished before spawning a new one.

However, time.sleep() can itself drift because no guarantees are made on how long the thread will actually be suspended. The correct way of doing it would be to figure out how long the job took and sleep for the remaining of the interval. I think this is how UI and game rendering engines work, where they have to display fixed number of frames per second at fixed times and rendering each frame could take different length of time to complete.

like image 148
Mansour Avatar answered Feb 12 '26 06:02

Mansour



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!