timer interrupt thread python

16,406

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.

Share:
16,406
Anders Cedronius
Author by

Anders Cedronius

I'm just another programmer. Started programing basic when I was 9 years old on my ATARI 800... Was later ranked as one of the worlds top 68000 assembler programmers when I was active in the demo group TCB (The CareBears - Atari ST). read more here -> https://www.microzeit.com/atari-store/volume-1/. Now it's Swift, Obj-C (Obj-C++), C, C++, Golang, Shaders and everything that comes in my way.

Updated on June 04, 2022

Comments

  • Anders Cedronius
    Anders Cedronius almost 2 years

    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

  • Anders Cedronius
    Anders Cedronius almost 11 years
    Ok. thanks. That's what I thought. I'll make some changes to my code in order to compensate for the execution time of the code in the thread.