Ich habe kürzlich eine Frage darüber, wie man die Ausführung einer Funktion in Python verschiebt (entspricht in etwa dem Javascript setTimeout
) und es stellt sich heraus, dass es eine einfache Aufgabe ist, die threading.Timer
(naja, einfach, solange die Funktion ihren Zustand nicht mit anderem Code teilt, aber das würde in jeder ereignisgesteuerten Umgebung Probleme verursachen).
Jetzt versuche ich, es besser zu machen und nachzumachen setInterval
. Für diejenigen, die mit Javascript nicht vertraut sind, setInterval
ermöglicht es, einen Funktionsaufruf alle x Sekunden zu wiederholen, ohne die Ausführung von anderem Code zu blockieren. Ich habe diesen Beispiel-Dekorator erstellt:
import time, threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times:
time.sleep(interval)
function(*args, **kwargs)
i += 1
threading.Timer(0, inner_wrap).start()
return wrap
return outer_wrap
die wie folgt zu verwenden sind
@setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
und es scheint mir, dass es gut funktioniert. Mein Problem ist, dass
- es scheint zu kompliziert zu sein, und ich fürchte, ich habe einen einfacheren/besseren Mechanismus übersehen
- der Dekorator kann ohne den zweiten Parameter aufgerufen werden, in diesem Fall wird er ewig weiterlaufen. Wenn ich foreover sage, meine ich für immer - sogar anrufen
sys.exit()
aus dem Haupt-Thread wird es nicht anhalten, ebenso wenig wie das Drücken vonCtrl+c
. Die einzige Möglichkeit, ihn zu stoppen, besteht darin, den Python-Prozess von außen zu beenden. Ich möchte in der Lage sein, ein Signal aus dem Hauptthread zu senden, das den Rückruf stoppen würde. Aber ich bin ein Anfänger mit Threads - wie kann ich zwischen ihnen kommunizieren?
EDIT Falls sich jemand wundert, dies ist die endgültige Version des Dekorators, dank der Hilfe von jd
import threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
stop = threading.Event()
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times and not stop.isSet():
stop.wait(interval)
function(*args, **kwargs)
i += 1
t = threading.Timer(0, inner_wrap)
t.daemon = True
t.start()
return stop
return wrap
return outer_wrap
Es kann mit einer festen Anzahl von Wiederholungen wie oben verwendet werden
@setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
oder kann bis zum Erhalt eines Stoppsignals laufen gelassen werden
import time
@setInterval(1)
def foo(a):
print(a)
stopper = foo('bar')
time.sleep(5)
stopper.set()
# It will stop here, after printing 'bar' 5 times.
0 Stimmen
Ich habe mir Ihren Code angeschaut und war etwas verwirrt, weil ich nicht gesehen habe, was die Schleife tatsächlich zum Anhalten bringt. Es schien mir, dass dies tatsächlich zu einer Schleife führen würde, die Folgendes aufruft
function
langsam bisstopper.set()
aufgerufen wird, wodurch die Schleife plötzlich beschleunigt würde! Ich habe es überprüft, und in der Tat, wenn Sie eine weiteretime.sleep(5)
nachstopper.set()
im obigen Beispiel ist genau das der Fall. Sie müssen eine Logik einbauen, um sicherzustellen, dass die Schleife anhält, sobaldstop.is_set()
wahr ist - z.B.while i != times and not stop.is_set():
0 Stimmen
Sie haben Recht, ich habe einen Absatz in der Dokumentation über die
wait()
Methode, und ich habe das Problem bei meinen Tests nicht erkannt. Ich werde den Code jetzt korrigieren.0 Stimmen
Ich habe die Antwort auf Ihre andere Frage das beweist wie man das Javascript emuliert
setInterval()
ohne Threads in Tkinter, Gtk, Twisted0 Stimmen
Hier ist ein einfach Ereignisbasiert
call_repeatedly(interval, func, *args)
Umsetzung