123 votes

threading.Timer - répéter la fonction toutes les 'n' secondes

Je veux déclencher une fonction toutes les 0,5 secondes et pouvoir démarrer, arrêter et réinitialiser le minuteur. Je ne suis pas trop au courant du fonctionnement des threads Python et j'ai des difficultés avec le timer Python.

Cependant, je continue à obtenir RuntimeError: threads can only be started once lorsque j'exécute threading.timer.start() deux fois. Existe-t-il un moyen de contourner ce problème ? J'ai essayé d'appliquer threading.timer.cancel() avant chaque départ.

Pseudo-code :

t=threading.timer(0.5,function)
while True:
    t.cancel()
    t.start()

140voto

Hans Then Points 5570

Le meilleur moyen est de lancer le fil de chronométrage une fois. À l'intérieur de votre fil de temporisation, vous coderez ce qui suit

class MyThread(Thread):
    def __init__(self, event):
        Thread.__init__(self)
        self.stopped = event

    def run(self):
        while not self.stopped.wait(0.5):
            print("my thread")
            # call a function

Dans le code qui a lancé la minuterie, vous pouvez alors set l'événement arrêté pour arrêter le minuteur.

stopFlag = Event()
thread = MyThread(stopFlag)
thread.start()
# this will stop the timer
stopFlag.set()

54voto

right2clicky Points 117

Améliorer un peu sur Réponse de Hans Then nous pouvons simplement sous-classer la fonction Timer. Ce qui suit devient notre tout le site "Il peut être utilisé comme un remplacement direct de threading.Timer avec les mêmes arguments :

from threading import Timer

class RepeatTimer(Timer):
    def run(self):
        while not self.finished.wait(self.interval):
            self.function(*self.args, **self.kwargs)

Exemple d'utilisation :

def dummyfn(msg="foo"):
    print(msg)

timer = RepeatTimer(1, dummyfn)
timer.start()
time.sleep(5)
timer.cancel()

produit la sortie suivante :

foo
foo
foo
foo

et

timer = RepeatTimer(1, dummyfn, args=("bar",))
timer.start()
time.sleep(5)
timer.cancel()

produit

bar
bar
bar
bar

38voto

J.F. Sebastian Points 102961

De Equivalent de setInterval en python :

import threading

def setInterval(interval):
    def decorator(function):
        def wrapper(*args, **kwargs):
            stopped = threading.Event()

            def loop(): # executed in another thread
                while not stopped.wait(interval): # until stopped
                    function(*args, **kwargs)

            t = threading.Thread(target=loop)
            t.daemon = True # stop if the program exits
            t.start()
            return stopped
        return wrapper
    return decorator

Utilisation :

@setInterval(.5)
def function():
    "..."

stop = function() # start timer, the first call is in .5 seconds
stop.set() # stop the loop
stop = function() # start new timer
# ...
stop.set() 

Ou voici la même fonctionnalité mais en tant que fonction autonome au lieu d'un décorateur :

cancel_future_calls = call_repeatedly(60, print, "Hello, World")
# ...
cancel_future_calls() 

Voici comment le faire sans utiliser de filets .

35voto

user1801431 Points 101

Utilisation de fils de minuterie-

from threading import Timer,Thread,Event

class perpetualTimer():

   def __init__(self,t,hFunction):
      self.t=t
      self.hFunction = hFunction
      self.thread = Timer(self.t,self.handle_function)

   def handle_function(self):
      self.hFunction()
      self.thread = Timer(self.t,self.handle_function)
      self.thread.start()

   def start(self):
      self.thread.start()

   def cancel(self):
      self.thread.cancel()

def printer():
    print 'ipsem lorem'

t = perpetualTimer(5,printer)
t.start()

cela peut être arrêté par t.cancel()

19voto

Bill Schumacher Points 61

Dans l'intérêt de fournir une réponse correcte en utilisant Timer comme l'OP l'a demandé, je vais améliorer les points suivants La réponse de swapnil jariwala :

from threading import Timer

class InfiniteTimer():
    """A Timer class that does not stop, unless you want it to."""

    def __init__(self, seconds, target):
        self._should_continue = False
        self.is_running = False
        self.seconds = seconds
        self.target = target
        self.thread = None

    def _handle_target(self):
        self.is_running = True
        self.target()
        self.is_running = False
        self._start_timer()

    def _start_timer(self):
        if self._should_continue: # Code could have been running when cancel was called.
            self.thread = Timer(self.seconds, self._handle_target)
            self.thread.start()

    def start(self):
        if not self._should_continue and not self.is_running:
            self._should_continue = True
            self._start_timer()
        else:
            print("Timer already started or running, please wait if you're restarting.")

    def cancel(self):
        if self.thread is not None:
            self._should_continue = False # Just in case thread is running and cancel fails.
            self.thread.cancel()
        else:
            print("Timer never started or failed to initialize.")

def tick():
    print('ipsem lorem')

# Example Usage
t = InfiniteTimer(0.5, tick)
t.start()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X