Search code examples
pythonmultithreadingtimerterminate

Python - how to terminate a threading.Timer class correctly?


I'm currently experimentating around with threading.Timer, and somehow I'm not doing very well.. My goal is to run hundreds of functions, repeating all the time. The problem is, that the usage of my RAM is growing and growing and growing, until the process stops.

This is how my code looks like:

from threading import Timer

class Foo:
    def __init__(self, number):
        self.number = number
        self.timer = Timer(1, self.print_number)
        self.timer.start()

    def print_number(self):
        print "Number: %s"%self.number
        self.repeat()

    def repeat(self):
        self.timer.cancel()
        #self.timer.join()
        #time.sleep(1)
        self.timer = Timer(3, self.print_number)
        self.timer.start()

for x in range(1, 300):
    Foo(x)

So, I've read that I can terminate a thread using .join() method after .cancel(). But when I do this I'm getting a RuntimeError: (cannot join current thread). On a similar topic I've read that I can use time.sleep after .cancel() to terminate a thread, but that does nothing to the thread for me.

My questions: How can I properly terminate the threads in this code example and how can I stop the script from using more and more RAM, or am I doing something terribly wrong?

Sorry if I'm re-asking a question that has been asked already many times, but I'm searching and trying for hours and couldn't find a solution yet.

Thanks in advance.


Solution

  • Something like this? Just have a break condition in the loop. The join at the end just makes sure all threads finish before moving forward. I use this often with a Queue (you can find samples, Queue Work Task pattern or some similar search).

    Alternatively, I use apscheduler when I just need things to run on a timer or some cron-like functionality.

    import threading
    import time
    
    WORKERS = 300
    
    class Worker(threading.Thread):
    
        def __init__(self, number):
            self.number = number
            threading.Thread.__init__(self)
    
        def run(self):
            while 1:
                if self.number > 300:
                    break
    
                print "Number: %s"%self.number
                self.number += 1
                time.sleep(3)
    
    workers = []
    for i in range(WORKERS):
        w = Worker(100)
        workers.append(w)
        w.start()
    
    for w in workers: 
        w.join()