0
votes

I found a solution for executing a function periodically every N seconds.

import threading;

def do_every (interval, worker_func, iterations = 0):
  if iterations != 1:
    threading.Timer (
      interval,
      do_every, [interval, worker_func, 0 if iterations == 0 else iterations-1]
    ).start ();

  worker_func ();

def print_hw ():
  print "hello world";

def print_so ():
  print "stackoverflow"


# call print_so every second, 5 times total
do_every (1, print_so, 5);

# call print_hw two times per second, forever
do_every (0.5, print_hw);

When we execute this code it start print "hello world" and "stackoverflow" at the moment execution (at time=0 seconds). What is the possible way to make it printat time=1 second and time=0.5 seconds (not starting at time=0 seconds) without using time.sleep

1

1 Answers

1
votes

I would be really hesitant to spawn a new Timer every single time. Timer extends Thread, and no one wants to start a new thread every few seconds.

If we look at the source code for Python, we can provide our own implementation for the Timer class. I don't know Python, so there may be a way to extend the class instead of basically copying all of its code.

The Timer class uses an Event (also in the threading module), to wait the specified amount of time.

import threading;
from threading import Thread;
from threading import Event;

#Extended from a class written by Itamar Shtull-Trauring
class MultiTimer(Thread):
    def __init__(self, interval, function, count = 0, args=None, kwargs=None):
        Thread.__init__(self)
        self.interval = interval
        self.function = function
        self.args = args if args is not None else []
        self.kwargs = kwargs if kwargs is not None else {}
        self.finished = Event()
        self.count = count
        self.infinite = count == 0

    def cancel(self):
        """Stop the timer if it hasn't finished yet."""
        self.finished.set()

    def run(self):
        while not self.finished.is_set():
            self.finished.wait(self.interval)
            if not self.finished.is_set():
                self.function(*self.args, **self.kwargs)
                self.decrementCount()

    def decrementCount(self):
        if not self.infinite:
            self.count -= 1
            if self.count == 0:
                self.finished.set()

def hello():
    print "hello, world"

#prints "hello, world" 3 times, at time = 2, 4, 6
t = MultiTimer(2.0, hello, 3)
t.start();

#never stops printing "hello, world" every 2 seconds
u = MultiTimer(2.0, hello)
u.start();