J'ai des difficultés avec le minuteur python et j'apprécierais beaucoup un conseil ou une aide: D
Je ne connais pas très bien le fonctionnement des threads, mais je souhaite simplement activer une fonction toutes les 0,5 seconde et pouvoir démarrer et arrêter le chronomètre et le réinitialiser.
Cependant, je continue à obtenir RuntimeError: threads can only be started once
lorsque j'exécute threading.timer.start()
deux fois. Y at-il un travail autour de cela? 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()
Le meilleur moyen est de démarrer le thread de la minuterie une fois. Dans votre fil de la minuterie, vous coderiez 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é le minuteur, vous pouvez alors set
l'événement arrêté pour l'arrêter.
stopFlag = Event()
thread = MyThread(stopFlag)
thread.start()
# this will stop the timer
stopFlag.set()
Utilisation de la 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()
From 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
Usage:
@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 les mêmes fonctionnalités mais en tant que fonction autonome au lieu de décorateur :
cancel_future_calls = call_repeatedly(60, print, "Hello, World")
# ...
cancel_future_calls()
Dans l’intérêt de fournir une réponse correcte en utilisant Timer comme le PO le demande, je vais améliorer la réponse de swapnil jariwala :
from threading import Timer
import time
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()
L'heure d'importation est facultative sans l'utilisation de l'exemple.
J'ai changé du code swapnil-jariwala pour créer une petite horloge de console.
from threading import Timer, Thread, Event
from datetime import datetime
class PT():
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 printer():
tempo = datetime.today()
h,m,s = tempo.hour, tempo.minute, tempo.second
print(f"{h}:{m}:{s}")
t = PT(1, printer)
t.start()
SORTIE
>>> 11:39:11
11:39:12
11:39:13
11:39:14
11:39:15
11:39:16
...
Ce code met la minuterie dans une petite fenêtre avec tkinter
from threading import Timer, Thread, Event
from datetime import datetime
import tkinter as tk
app = tk.Tk()
lab = tk.Label(app, text="Timer will start in a sec")
lab.pack()
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():
tempo = datetime.today()
clock = "{}:{}:{}".format(tempo.hour, tempo.minute, tempo.second)
try:
lab['text'] = clock
except RuntimeError:
exit()
t = perpetualTimer(1, printer)
t.start()
app.mainloop()
from threading import Timer, Thread, Event
from datetime import datetime
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()
x = datetime.today()
start = x.second
def printer():
global questions, counter, start
x = datetime.today()
tempo = x.second
if tempo - 3 > start:
show_ans()
#print("\n{}:{}:{}".format(tempo.hour, tempo.minute, tempo.second), end="")
print()
print("-" + questions[counter])
counter += 1
if counter == len(answers):
counter = 0
def show_ans():
global answers, c2
print("It is {}".format(answers[c2]))
c2 += 1
if c2 == len(answers):
c2 = 0
questions = ["What is the capital of Italy?",
"What is the capital of France?",
"What is the capital of England?",
"What is the capital of Spain?"]
answers = "Rome", "Paris", "London", "Madrid"
counter = 0
c2 = 0
print("Get ready to answer")
t = perpetualTimer(3, printer)
t.start()
sortie:
Get ready to answer
>>>
-What is the capital of Italy?
It is Rome
-What is the capital of France?
It is Paris
-What is the capital of England?
...
Améliorer un peu sur La réponse de Hans Then , nous pouvons simplement sous-classer la fonction Minuterie. Ce qui suit devient notre code entier "Repeat timer", et il peut être utilisé comme remplacement instantané 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
Je devais le faire pour un projet. Ce que j'ai fini par faire, c'est de lancer un thread séparé pour la fonction
t = threading.Thread(target =heartbeat, args=(worker,))
t.start()
**** le battement de coeur est ma fonction, le travailleur est l'un de mes arguments ****
à l'intérieur de ma fonction de battement de coeur:
def heartbeat(worker):
while True:
time.sleep(5)
#all of my code
Ainsi, lorsque je démarre le thread, la fonction attend 5 secondes à plusieurs reprises, exécute tout mon code et le fait indéfiniment. Si vous voulez tuer le processus, tuez simplement le fil.
J'ai implémenté une classe qui fonctionne comme une minuterie.
Je laisse le lien ici au cas où quelqu'un en aurait besoin: https://github.com/ivanhalencp/python/tree/master/xTimer
J'aime la réponse de right2clicky, notamment parce qu'elle n'exige pas qu'un fil soit déchiré et qu'un nouveau soit créé chaque fois que le minuteur se déclenche. En outre, il est facile de créer une classe avec un rappel de minuterie appelé périodiquement. C'est mon cas d'utilisation normal:
class MyClass(RepeatTimer):
def __init__(self, period):
super().__init__(period, self.on_timer)
def on_timer(self):
print("Tick")
if __== "__main__":
mc = MyClass(1)
mc.start()
time.sleep(5)
mc.cancel()
from threading import Timer
def TaskManager():
#do stuff
t = Timer( 1, TaskManager )
t.start()
TaskManager()
Voici un petit exemple, il aidera à mieux comprendre comment il s'exécute . Function taskManager () à la fin de créer un appel de fonction retardé.
Essayez de changer la variable "dalay" et vous pourrez voir la différence
from threading import Timer, _sleep
# ------------------------------------------
DATA = []
dalay = 0.25 # sec
counter = 0
allow_run = True
FIFO = True
def taskManager():
global counter, DATA, delay, allow_run
counter += 1
if len(DATA) > 0:
if FIFO:
print("["+str(counter)+"] new data: ["+str(DATA.pop(0))+"]")
else:
print("["+str(counter)+"] new data: ["+str(DATA.pop())+"]")
else:
print("["+str(counter)+"] no data")
if allow_run:
#delayed method/function call to it self
t = Timer( dalay, taskManager )
t.start()
else:
print(" END task-manager: disabled")
# ------------------------------------------
def main():
DATA.append("data from main(): 0")
_sleep(2)
DATA.append("data from main(): 1")
_sleep(2)
# ------------------------------------------
print(" START task-manager:")
taskManager()
_sleep(2)
DATA.append("first data")
_sleep(2)
DATA.append("second data")
print(" START main():")
main()
print(" END main():")
_sleep(2)
DATA.append("last data")
allow_run = False
Ceci est une autre implémentation utilisant function au lieu de class. Inspiré par @ Andrew Wilkins ci-dessus.
Parce que wait est plus précis que dormir (cela prend en compte l'exécution de la fonction):
import threading
PING_ON = threading.Event()
def ping():
while not PING_ON.wait(1):
print("my thread %s" % str(threading.current_thread().ident))
t = threading.Thread(target=ping)
t.start()
sleep(5)
PING_ON.set()