Sie können das Signalpaket verwenden , wenn Sie unter UNIX arbeiten:
In [1]: import signal
# Register an handler for the timeout
In [2]: def handler(signum, frame):
...: print("Forever is over!")
...: raise Exception("end of time")
...:
# This function *may* run for an indetermined time...
In [3]: def loop_forever():
...: import time
...: while 1:
...: print("sec")
...: time.sleep(1)
...:
...:
# Register the signal function handler
In [4]: signal.signal(signal.SIGALRM, handler)
Out[4]: 0
# Define a timeout for your function
In [5]: signal.alarm(10)
Out[5]: 0
In [6]: try:
...: loop_forever()
...: except Exception, exc:
...: print(exc)
....:
sec
sec
sec
sec
sec
sec
sec
sec
Forever is over!
end of time
# Cancel the timer if the function returned before timeout
# (ok, mine won't but yours maybe will :)
In [7]: signal.alarm(0)
Out[7]: 0
10 Sekunden nach dem Aufruf alarm.alarm(10)
wird der Handler aufgerufen. Dies löst eine Ausnahme aus, die Sie vom regulären Python-Code abfangen können.
Dieses Modul spielt nicht gut mit Threads (aber wer dann?)
Beachten Sie, dass eine Ausnahme, wenn eine Zeitüberschreitung auftritt, möglicherweise innerhalb der Funktion abgefangen und ignoriert wird, z. B. bei einer solchen Funktion:
def loop_forever():
while 1:
print('sec')
try:
time.sleep(10)
except:
continue
signal.alarm
und die dazugehörigenSIGALRM
sind auf Windows-Plattformen nicht verfügbar.signal.signal
--- funktionieren sie alle richtig? Wird nicht jedersignal.signal
Anruf "gleichzeitig" abgebrochen?Sie können
multiprocessing.Process
genau das verwenden.Code
quelle
join()
. Dadurch wird Ihre x-Anzahl gleichzeitiger Unterprozesse ausgeführt, bis sie ihre Arbeit beendet haben, oder die in definierte Mengejoin(10)
. Wenn Sie eine blockierende E / A für 10 Prozesse haben, haben Sie sie mit join (10) so eingestellt, dass sie alle maximal 10 auf JEDEN Prozess warten, der gestartet wurde. Verwenden Sie das Daemon-Flag wie in diesem Beispiel stackoverflow.com/a/27420072/2480481 . Natürlich können Sie das Flagdaemon=True
direkt an diemultiprocessing.Process()
Funktion übergeben.terminate() ... Note that exit handlers and finally clauses, etc., will not be executed. Note that descendant processes of the process will not be terminated – they will simply become orphaned.
Ich habe einen Kern gepostet , der diese Frage / dieses Problem mit einem Dekorateur und einem löst
threading.Timer
. Hier ist es mit einer Panne.Importe und Setups aus Kompatibilitätsgründen
Es wurde mit Python 2 und 3 getestet. Es sollte auch unter Unix / Linux und Windows funktionieren.
Zuerst die Importe. Diese versuchen, den Code unabhängig von der Python-Version konsistent zu halten:
Verwenden Sie den versionunabhängigen Code:
Jetzt haben wir unsere Funktionalität aus der Standardbibliothek importiert.
exit_after
DekorateurAls nächstes benötigen wir eine Funktion, um den
main()
vom untergeordneten Thread zu beenden :Und hier ist der Dekorateur selbst:
Verwendung
Und hier ist die Verwendung, die Ihre Frage zum Beenden nach 5 Sekunden direkt beantwortet!:
Demo:
Der zweite Funktionsaufruf wird nicht beendet, stattdessen sollte der Prozess mit einem Traceback beendet werden!
KeyboardInterrupt
stoppt nicht immer einen schlafenden FadenBeachten Sie, dass der Ruhezustand unter Python 2 unter Windows nicht immer durch einen Tastaturinterrupt unterbrochen wird, z.
Es ist auch nicht wahrscheinlich, dass Code, der in Erweiterungen ausgeführt wird, unterbrochen wird, es sei denn, er prüft explizit
PyErr_CheckSignals()
, ob Cython, Python und KeyboardInterrupt ignoriert werdenIch würde es auf jeden Fall vermeiden, einen Thread länger als eine Sekunde zu schlafen - das ist ein Äon in der Prozessorzeit.
Um es zu fangen und etwas anderes zu tun, können Sie den KeyboardInterrupt fangen.
quelle
thread.interrupt_main()
, warum kann ich keine Ausnahme direkt auslösen?multiprocessing.connection.Client
dazu? - Versuch zu lösen: stackoverflow.com/questions/57817955/…Ich habe einen anderen Vorschlag, der eine reine Funktion ist (mit der gleichen API wie der Threading-Vorschlag) und anscheinend gut funktioniert (basierend auf Vorschlägen zu diesem Thread).
quelle
timeout
. Es ist viel besser, die Standardeinstellung auf zu setzenNone
und in der ersten Zeile der Funktion hinzuzufügenkwargs = kwargs or {}
. Args ist in Ordnung, da Tupel nicht veränderlich sind.Ich bin auf diesen Thread gestoßen, als ich bei Unit-Tests nach einem Timeout-Aufruf gesucht habe. Ich habe in den Antworten oder Paketen von Drittanbietern nichts Einfaches gefunden, also habe ich den Dekorateur unten geschrieben, den Sie direkt in den Code einfügen können:
Dann ist es so einfach, einen Test oder eine beliebige Funktion zu deaktivieren:
quelle
Exception
innerhalb von func_wrapper zupool.close()
fangen, und nach dem Fang tun, um sicherzustellen, dass der Thread immer danach stirbt, egal was passiert . Dann kannst du werfenTimeoutError
oder was immer du willst. Scheint für mich zu arbeiten.RuntimeError: can't start new thread
. Funktioniert es immer noch, wenn ich es ignoriere, oder kann ich noch etwas tun, um dies zu umgehen? Danke im Voraus!Das
stopit
auf pypi gefundene Paket scheint Timeouts gut zu verarbeiten.Ich mag den
@stopit.threading_timeoutable
Dekorator, dertimeout
der dekorierten Funktion einen Parameter hinzufügt , der das tut, was Sie erwarten, er stoppt die Funktion.Überprüfen Sie es auf pypi: https://pypi.python.org/pypi/stopit
quelle
Es gibt viele Vorschläge, aber keine, die concurrent.futures verwenden. Ich denke, dies ist der am besten lesbare Weg, um damit umzugehen.
Super einfach zu lesen und zu warten.
Wir erstellen einen Pool, senden einen einzelnen Prozess und warten dann bis zu 5 Sekunden, bevor wir einen TimeoutError auslösen, den Sie nach Bedarf abfangen und verarbeiten können.
Nativ in Python 3.2+ und zurückportiert auf 2.7 (Pip Install Futures).
Das Wechseln zwischen Threads und Prozessen ist so einfach wie das Ersetzen
ProcessPoolExecutor
durchThreadPoolExecutor
.Wenn Sie den Prozess mit Zeitüberschreitung beenden möchten, würde ich empfehlen, sich mit Pebble zu befassen .
quelle
Großartiger, benutzerfreundlicher und zuverlässiger Timeout-Dekorator für PyPi- Projekte ( https://pypi.org/project/timeout-decorator/ )
Installation :
Verwendung :
quelle
Ich bin der Autor von wrapt_timeout_decorator
Die meisten der hier vorgestellten Lösungen funktionieren auf den ersten Blick wunderbar unter Linux - weil wir Fork () und Signale () haben -, aber unter Windows sehen die Dinge etwas anders aus. Und wenn es um Subthreads unter Linux geht, können Sie keine Signale mehr verwenden.
Um einen Prozess unter Windows zu erzeugen, muss er auswählbar sein - und viele dekorierte Funktionen oder Klassenmethoden nicht.
Sie müssen also einen besseren Pickler wie Dill und Multiprocess verwenden (nicht Pickle und Multiprocessing) - deshalb können Sie ProcessPoolExecutor nicht verwenden (oder nur mit eingeschränkter Funktionalität).
Für das Timeout selbst - Sie müssen definieren, was Timeout bedeutet -, da unter Windows eine beträchtliche (und nicht bestimmbare) Zeit benötigt wird, um den Prozess zu erzeugen. Dies kann bei kurzen Zeitüberschreitungen schwierig sein. Nehmen wir an, das Laichen des Prozesses dauert ungefähr 0,5 Sekunden (leicht !!!). Wenn Sie eine Zeitüberschreitung von 0,2 Sekunden angeben, was soll passieren? Sollte die Funktion nach 0,5 + 0,2 Sekunden ablaufen (lassen Sie die Methode also 0,2 Sekunden lang laufen)? Oder sollte der aufgerufene Prozess nach 0,2 Sekunden eine Zeitüberschreitung aufweisen (in diesem Fall wird die dekorierte Funktion IMMER eine Zeitüberschreitung aufweisen, da sie in dieser Zeit nicht einmal erzeugt wird)?
Auch verschachtelte Dekorateure können böse sein und Sie können keine Signale in einem Unterfaden verwenden. Wenn Sie einen wirklich universellen, plattformübergreifenden Dekorateur erstellen möchten, muss dies alles berücksichtigt (und getestet) werden.
Andere Probleme sind die Rückgabe von Ausnahmen an den Aufrufer sowie Protokollierungsprobleme (falls in der dekorierten Funktion verwendet - die Protokollierung in Dateien in einem anderen Prozess wird NICHT unterstützt)
Ich habe versucht, alle Randfälle abzudecken. Sie könnten in das Paket wrapt_timeout_decorator schauen oder zumindest Ihre eigenen Lösungen testen, die von den dort verwendeten Unittests inspiriert sind.
@Alexis Eggermont - leider habe ich nicht genug Punkte zum Kommentieren - vielleicht kann dich jemand anderes benachrichtigen - ich glaube, ich habe dein Importproblem gelöst.
quelle
timeout-decorator
funktioniert nicht auf Windows-System, da Windows nichtsignal
gut unterstützt.Wenn Sie Timeout-Decorator im Windows-System verwenden, erhalten Sie Folgendes
Einige schlugen vor, zu verwenden
use_signals=False
, arbeiteten aber nicht für mich.Der Autor @bitranox hat das folgende Paket erstellt:
Codebeispiel:
Gibt die folgende Ausnahme:
quelle
from wrapt_timeout_decorator import *
scheint die Linie einige meiner anderen Importe zu töten. Zum Beispiel bekomme ichModuleNotFoundError: No module named 'google.appengine'
, aber ich bekomme diesen Fehler nicht, wenn ich wrapt_timeout_decorator nicht importiereWir können Signale dafür verwenden. Ich denke, das folgende Beispiel wird für Sie nützlich sein. Es ist sehr einfach im Vergleich zu Threads.
quelle
try: ... except: ...
sind immer eine schlechte Idee.quelle
Ich brauchte verschachtelbare zeitgesteuerte Interrupts (was SIGALARM nicht kann), die nicht durch time.sleep blockiert werden (was der threadbasierte Ansatz nicht kann). Am Ende habe ich Code von hier kopiert und leicht modifiziert: http://code.activestate.com/recipes/577600-queue-for-managing-multiple-sigalrm-alarms-concurr/
Der Code selbst:
und ein Anwendungsbeispiel:
quelle
Hier ist eine leichte Verbesserung der gegebenen threadbasierten Lösung.
Der folgende Code unterstützt Ausnahmen :
Aufrufen mit einer Zeitüberschreitung von 5 Sekunden:
quelle
runFunctionCatchExceptions()
bestimmter Python-Funktionen das Erhalten von GIL aufgerufen wird. Zum Beispiel würde das Folgende niemals oder für sehr lange Zeit zurückkehren, wenn es innerhalb der Funktion aufgerufen wird :eval(2**9999999999**9999999999)
. Siehe stackoverflow.com/questions/22138190/…