Ich möchte eine Funktion in Python alle 60 Sekunden für immer wiederholt ausführen (genau wie ein NSTimer in Ziel C). Dieser Code wird als Daemon ausgeführt und entspricht praktisch dem Aufrufen des Python-Skripts jede Minute mit einem Cron, ohne dass dies vom Benutzer eingerichtet werden muss.
In dieser Frage zu einem in Python implementierten Cron scheint die Lösung effektiv nur x Sekunden lang zu schlafen () . Ich brauche keine so erweiterte Funktionalität, also würde so etwas vielleicht funktionieren
while True:
# Code executed here
time.sleep(60)
Gibt es vorhersehbare Probleme mit diesem Code?
time.sleep(60)
zurückgeben kann sowohl früher und späterAntworten:
Wenn Ihr Programm noch keine Ereignisschleife hat, verwenden Sie das Schedul- Modul, das einen Allzweck-Event-Scheduler implementiert.
Wenn Sie bereits eine Event Loop - Bibliothek wie mit
asyncio
,trio
,tkinter
,PyQt5
,gobject
,kivy
, und viele andere - planen nur die Aufgabe , Ihre vorhandenen Ereignisschleife Bibliothek Methoden verwenden, statt.quelle
enterabs()
, um es zu vermeiden. Hier ist eine nicht driftende Version zum Vergleich .time.sleep
sich hier Fehler von ansammeln können. "Alle X Sekunden ausführen" und "Immer wieder mit einer Verzögerung von ~ X Sekunden ausführen" sind nicht dasselbe. Siehe auch diesen KommentarSperren Sie einfach Ihre Zeitschleife auf die Systemuhr. Einfach.
quelle
twisted
Antwort sind die einzigen Antworten, die allex
Sekunden eine Funktion ausführen . Der Rest führt die Funktion mit einer Verzögerung vonx
Sekunden nach jedem Aufruf aus.from time import time, sleep
wegen der existenziellen Implikationen;)starttime
wenn Sie mit der Synchronisierung zu einer bestimmten Zeit beginnen:time.sleep(60 - time.time() % 60)
hat für mich gut funktioniert. Ich habe es als verwendettime.sleep(1200 - time.time() % 1200)
und es gibt mir Protokolle auf dem:00 :20 :40
, genau wie ich wollte.sleep()
,timer()
Präzision und wie lange es dauert , die Schleife zu überführen , aber im Durchschnitt Iterationen immer dann auftreten , auf den Intervallgrenzen (auch wenn einige übersprungen):while keep_doing_it(): sleep(interval - timer() % interval)
. Vergleichen Sie es damit,while keep_doing_it(): sleep(interval)
wo sich nach mehreren Iterationen Fehler ansammeln können.Vielleicht möchten Sie Twisted in Betracht ziehen , eine Python-Netzwerkbibliothek, die das Reaktormuster implementiert .
Während "while True: sleep (60)" wahrscheinlich funktioniert, implementiert Twisted wahrscheinlich bereits viele der Funktionen, die Sie möglicherweise benötigen (Dämonisierung, Protokollierung oder Ausnahmebehandlung, wie von Bobince hervorgehoben), und ist wahrscheinlich eine robustere Lösung
quelle
Wenn Sie möchten, dass Ihre Funktion nicht blockierend ausgeführt wird, würde ich anstelle einer blockierenden Endlosschleife einen Thread-Timer verwenden. Auf diese Weise kann Ihr Code weiter ausgeführt werden und andere Aufgaben ausführen, und Ihre Funktion wird weiterhin alle n Sekunden aufgerufen. Ich verwende diese Technik häufig zum Drucken von Fortschrittsinformationen bei langen, CPU / Disk / Netzwerk-intensiven Aufgaben.
Hier ist der Code, den ich in einer ähnlichen Frage mit der Steuerung start () und stop () gepostet habe:
Verwendungszweck:
Eigenschaften:
start()
und könnenstop()
sicher mehrmals angerufen werden, auch wenn der Timer bereits gestartet / gestoppt wurdeinterval
jederzeit ändern , es wird nach dem nächsten Lauf wirksam. Das Gleiche gilt fürargs
,kwargs
und sogarfunction
!quelle
def _run(self)
Ich versuche , meinen Kopf herum zu wickeln , warum Sie rufenself.start()
vorself.function()
. Können Sie das näher erläutern? Ich würde denken, wenn wirstart()
zuerst anrufen,self.is_running
wäre das immerFalse
so, dann würden wir immer einen neuen Thread aufbauen.x
Sekunden eine Funktion aus (dh t = 0, t = 1x, t = 2x, t = 3x, ...), wobei auf den Originalplakaten im Beispielcode eine Funktion mit einem Intervall von x Sekunden dazwischen ausgeführt wird. Außerdem hat diese Lösung meines Erachtens einen Fehler, wenn sieinterval
kürzer als diefunction
Ausführungszeit ist. In diesem Fallself._timer
wird in derstart
Funktion überschrieben ..function()
after.start()
besteht darin, die Funktion bei t = 0 auszuführen. Und ich denke nicht, dass es ein Problem sein wird, wenn esfunction
länger dauert alsinterval
, aber ja, es könnte einige Rennbedingungen im Code geben.Der einfachere Weg, den ich glaube:
Auf diese Weise wird Ihr Code ausgeführt, dann wartet er 60 Sekunden, dann wird er erneut ausgeführt, wartet, wird ausgeführt usw. Keine Notwendigkeit, Dinge zu komplizieren: D.
quelle
time.sleep()
alle X Sekunden laufen etwastime.sleep()
in einerwhile True
Schleife aufgerufen werden wie:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Wenn Sie dies tun möchten, ohne den verbleibenden Code zu blockieren, können Sie ihn verwenden, um ihn in einem eigenen Thread ausführen zu lassen:
Diese Lösung kombiniert mehrere Funktionen, die in den anderen Lösungen selten zu finden sind:
threading.Timer
, als die Kette beendet wird , wenn innerhalb des Planungsmechanismus ( oder was auch immer) etwas schief geht . Es werden dann keine weiteren Ausführungen stattfinden, selbst wenn der Grund des Problems bereits behoben ist. Eine einfache Schleife und Warten mit einer einfachensleep()
ist im Vergleich viel robuster.next_time += delay
statt.quelle
Hier ist ein Update des Codes von MestreLion, das ein Drifitieren im Laufe der Zeit vermeidet.
Die RepeatedTimer-Klasse ruft hier die angegebene Funktion alle "Intervall" Sekunden auf, wie vom OP angefordert; Der Zeitplan hängt nicht davon ab, wie lange die Ausführung der Funktion dauert. Ich mag diese Lösung, da sie keine externen Bibliotheksabhängigkeiten hat. Das ist nur reine Python.
Beispielnutzung (kopiert aus der Antwort von MestreLion):
quelle
Ich hatte vor einiger Zeit ein ähnliches Problem. Kann sein http://cronus.readthedocs.org helfen könnten?
Für v0.2 funktioniert das folgende Snippet
quelle
Der Hauptunterschied zwischen diesem und cron besteht darin, dass eine Ausnahme den Dämon endgültig tötet. Möglicherweise möchten Sie mit einem Ausnahmefänger und einem Logger umbrechen.
quelle
Eine mögliche Antwort:
quelle
Am Ende habe ich das Zeitplanmodul verwendet . Die API ist nett.
quelle
Ich verwende die Tkinter after () -Methode, die das Spiel nicht "stiehlt" (wie das zuvor vorgestellte Sched- Modul), dh andere Dinge können parallel ausgeführt werden:
do_something1()
unddo_something2()
kann parallel und in jeder Intervallgeschwindigkeit laufen. Hier wird der zweite doppelt so schnell ausgeführt. Beachten Sie auch, dass ich einen einfachen Zähler als Bedingung verwendet habe, um eine der beiden Funktionen zu beenden. Sie können jede andere oder keine beliebige Bedingung verwenden, wenn Sie eine Funktion ausführen möchten, bis das Programm endet (z. B. eine Uhr).quelle
after
Erlaubt nicht, dass Dinge parallel laufen. Tkinter ist Single-Threaded und kann jeweils nur eine Aufgabe ausführen. Wenn etwas ausgeführt wird, das von geplantafter
ist, wird es nicht parallel zum Rest des Codes ausgeführt. Wenn beidedo_something1
unddo_something2
gleichzeitig ausgeführt werden sollen, werden sie nacheinander und nicht parallel ausgeführt.sched
Lösung verwenden und sie funktioniert genauso wie Ihre.Hier ist eine angepasste Version des Codes von MestreLion. Zusätzlich zur ursprünglichen Funktion enthält dieser Code:
1) Fügen Sie das erste Intervall hinzu, mit dem der Timer zu einem bestimmten Zeitpunkt ausgelöst wird (der Anrufer muss das erste Intervall berechnen und übergeben).
2) Löse eine Rennbedingung im Originalcode. Wenn der ursprüngliche Thread im ursprünglichen Code den laufenden Timer nicht abbrechen konnte ("Stoppen Sie den Timer und brechen Sie die Ausführung der Timer-Aktion ab. Dies funktioniert nur, wenn sich der Timer noch in der Wartephase befindet.", Zitiert aus https: // docs.python.org/2/library/threading.html ) läuft der Timer endlos.
quelle
Dies scheint viel einfacher zu sein als eine akzeptierte Lösung - hat sie Mängel, die ich nicht in Betracht ziehe? Kam hierher auf der Suche nach einer absolut einfachen Kopie Pasta und war enttäuscht.
Welche asynchron ausgegeben.
Es hat eine Drift in dem Sinne, dass, wenn die ausgeführte Aufgabe eine beträchtliche Zeit in Anspruch nimmt, das Intervall 2 Sekunden + Aufgabenzeit beträgt. Wenn Sie also eine genaue Planung benötigen, ist dies nichts für Sie.
Beachten Sie, dass das
daemon=True
Flag bedeutet, dass dieser Thread das Herunterfahren der App nicht blockiert. Hatte zum Beispiel ein Problem, wopytest
es unbegrenzt hängen würde, nachdem Tests ausgeführt wurden, die darauf warteten, dass dieser Kopf aufhörte.quelle
Ich benutze dies, um 60 Ereignisse pro Stunde zu verursachen, wobei die meisten Ereignisse nach der ganzen Minute in der gleichen Anzahl von Sekunden auftreten:
Abhängig von den tatsächlichen Bedingungen können Zecken mit einer Länge von:
Aber nach 60 Minuten haben Sie 60 Zecken. und die meisten von ihnen treten mit dem richtigen Versatz zu der Minute auf, die Sie bevorzugen.
Auf meinem System erhalte ich eine typische Drift von <1/20 Sekunde, bis Korrekturbedarf besteht.
Der Vorteil dieser Methode ist die Auflösung der Taktdrift; Dies kann zu Problemen führen, wenn Sie beispielsweise einen Artikel pro Tick anhängen und 60 Artikel pro Stunde anhängen. Wenn die Drift nicht berücksichtigt wird, können sekundäre Anzeigen wie gleitende Durchschnitte dazu führen, dass Daten zu tief in der Vergangenheit liegen, was zu einer fehlerhaften Ausgabe führt.
quelle
Beispiel: Aktuelle Ortszeit anzeigen
quelle
quelle
Hier ist eine andere Lösung ohne zusätzliche Bibliotheken.
quelle