Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - threading.Timer stays alive after calling cancel() method

I noticed the following behavior in the following code (using threading.Timer class):

import threading

def ontimer():
    print threading.current_thread()

def main():
    timer = threading.Timer(2, ontimer)
    timer.start()
    print threading.current_thread()
    timer.cancel()
    if timer.isAlive():
        print "Timer is still alive"
    if timer.finished:
        print "Timer is finished"


 if __name__ == "__main__":
main()

The output of the code is:

<_MainThread(MainThread, started 5836)>
Timer is still alive
Timer is finished

As We notice from the output, that the timer object is still alive and finished in the same time.

In fact, I would like to call a similar function hundreds of times, and I wonder whether those "living" timers may affect the performance.

I would like to stop or cancel the timer object in a proper way. Am I doing it right?

Thank you

like image 788
Ababneh A Avatar asked Jun 18 '12 12:06

Ababneh A


2 Answers

You should use the thread.join() to wait until your timer's thread is really finished and cleaned.

import threading

def ontimer():
    print threading.current_thread()

def main():
    timer = threading.Timer(2, ontimer)
    timer.start()
    print threading.current_thread()
    timer.cancel()
    timer.join()         # here you block the main thread until the timer is completely stopped
    if timer.isAlive():
        print "Timer is still alive"
    else:
        print "Timer is no more alive"
    if timer.finished:
        print "Timer is finished"


 if __name__ == "__main__":
main()

This will display :

<_MainThread(MainThread, started 5836)>
Timer is no more alive
Timer is finished
like image 141
Cédric Julien Avatar answered Oct 21 '22 03:10

Cédric Julien


A Timer is a subclass of a Thread and its implementation is really simple. It waits the provided time by subscribing to the event finished.

So when you set the event by Timer.cancel it is guaranteed that the function does not get called. But it is not guaranteed that the Timer thread will directly continue (and exit).

So the point is that the thread of the timer can still be alive after the execution of cancel, but the function will not get executed. So checking for finished is safe, while testing for Thread.is_alive (newer API, use this!) is a race condition in this case.

Hint: You can verify this by placing a time.sleep after calling cancel. Then it will just print:

<_MainThread(MainThread, started 10872)>
Timer is finished
like image 13
schlamar Avatar answered Oct 21 '22 03:10

schlamar