Tastatur-Interrupts mit python-multiprocessing-Pool
Wie kann ich damit umgehen KeyboardInterrupt Veranstaltungen mit python-multiprocessing-Pools? Hier ist ein einfaches Beispiel:
from multiprocessing import Pool
from time import sleep
from sys import exit
def slowly_square(i):
sleep(1)
return i*i
def go():
pool = Pool(8)
try:
results = pool.map(slowly_square, range(40))
except KeyboardInterrupt:
# **** THIS PART NEVER EXECUTES. ****
pool.terminate()
print "You cancelled the program!"
sys.exit(1)
print "\nFinally, here are the results: ", results
if __name__ == "__main__":
go()
Beim ausführen des Codes über die KeyboardInterrupt
ausgelöst wird, wenn ich drücken Sie ^C
, aber der Prozess hängt einfach an diesem Punkt und ich habe es zu töten extern.
Ich möchte in der Lage sein zu drücken ^C
zu jeder Zeit und dazu führen, dass alle Prozesse ordnungsgemäß beendet werden.
Ich löste mein problem mit psutil, können Sie sehen, die Lösung hier: stackoverflow.com/questions/32160054/...
InformationsquelleAutor Fragsworth | 2009-09-10
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dies ist ein Python bug. Beim warten auf einen Zustand, in dem threading.Zustand.wait(), KeyboardInterrupt nie gesendet. Repro:
Die KeyboardInterrupt-Ausnahme, werden nicht übermittelt, bis wait() kehrt zurück, und es kehrt nie zurück, so wird der interrupt nie passiert. KeyboardInterrupt sollte fast sicher unterbrechen, eine Bedingung warten.
Beachten Sie, dass dies nicht der Fall, wenn ein timeout angegeben ist; cond.warten(1), erhalten den interrupt sofort aus. Also, ein workaround ist die Angabe eines timeout. Um das zu tun, ersetzen
mit
oder ähnliches.
Dieser Fehler wurde abgelegt als [Ausgabe 8296][1]. [1]: bugs.python.org/issue8296
Diese nicht ganz fix Dinge. Manchmal bekomme ich das erwartete Verhalten, wenn ich drücken Sie Strg+C, das andere mal nicht. Ich bin mir nicht sicher, warum, aber es sieht aus wie vielleicht Die KeyboardInterrupt ist, erhalten durch eines der Verfahren nach dem Zufallsprinzip, und ich bekomme nur das richtige Verhalten, wenn der parent-Prozess ist derjenige, der fängt ihn auf.
soweit ich weiß ist dieses system ausdrücklich erlaubt zu Bearbeiten, die anderen Beiträge zu verbessern. So sehe ich nicht wirklich das problem, lassen Sie mich verweisen Sie auf: stackoverflow.com/tour
ich habe gerade den link Hinzugefügt, um Ihr Problem erwähnt für godssake! Und da solltest erhebliche Freiheit genommen, fügen Sie einige tags zur Formatierung. Die ist auch in SO-Regelbuch.
InformationsquelleAutor Glenn Maynard
Ab, was ich vor kurzem gefunden, die beste Lösung ist, um die Arbeitsprozesse zu ignorieren SIGINT insgesamt, und darauf beschränken, alle cleanup-code, um den übergeordneten Prozess. Dies behebt das problem für Leerlauf und beschäftigt Arbeitsprozesse und erfordert keine error-handling-code in Ihre Kind-Prozesse.
Erläuterung und vollständige Codebeispiel finden Sie unter http://noswap.com/blog/python-multiprocessing-keyboardinterrupt/ und http://github.com/jreese/multiprocessing-keyboardinterrupt bzw.
time.sleep(10)
in der main-Prozess. Wenn Sie zu entfernen, schlafen, oder wenn Sie warten, bis der Prozess versucht, um uns auf den pool, die Sie tun müssen, um sicherzustellen, dass die Aufträge abgeschlossen sind, dann sind Sie immer noch unter dem gleichen problem leiden, das ist der wichtigste Prozess nicht erhalten KeyboardInterrupt, während Sie warten auf eine Umfragejoin
Betrieb.In dem Fall, wo ich dieses code in der Produktion, die Zeit.sleep() war Teil einer Schleife, die würde überprüfen Sie den status von jeder Kind-Prozess, und dann neu starten, bestimmte Prozesse auf eine Verzögerung, wenn erforderlich. Anstatt join() , würde warten, bis alle Prozesse abgeschlossen, es wäre zu überprüfen, auf Sie individuell, sicherzustellen, dass der master-Prozess blieb zu reagieren.
Es war also mehr ein busy wait (vielleicht mit kleiner schläft zwischen den Prüfungen), dass die Befragten für den Abschluss eines Prozesses über eine andere Methode anstatt kommen? Wenn das der Fall ist, vielleicht wäre es besser, diesen code in Ihrem blog veröffentlichen, da können Sie dann garantieren, dass alle Arbeitnehmer abgeschlossen haben, bevor Sie versuchen, zu verbinden.
Und das funktioniert nicht. Nur die Kinder geschickt werden, das signal. Der Elternteil erhält nie, so
pool.terminate()
wird nie ausgeführt. Nachdem die Kinder ignorieren das signal, leistet nichts. @Glenn ' s Antwort löst das problem.Meine version ist im gist.github.com/admackin/003dd646e5fadee8b8d6 ; es nicht nennen
.join()
außer auf interrupt - einfach manuell überprüft, das Ergebnis.apply_async()
mitAsyncResult.ready()
um zu sehen, wenn es fertig ist, was bedeutet, wir haben sauber beendet.InformationsquelleAutor John Reese
Einige Gründe, nur Ausnahmen geerbt von der Basis
Exception
Klasse werden normal behandelt. Als workaround, können Sie re-raise yourKeyboardInterrupt
alsException
Beispiel:Normalerweise würden Sie die folgende Ausgabe erhalten:
Also, wenn Sie Treffer
^C
erhalten Sie:KeyboardInterrupt
angekommen ist, währendmultiprocessing
ist die Durchführung der IPC data exchange dann dietry..catch
wird nicht aktiviert (offensichtlich).Dies funktionierte gut für mich.
Sie ersetzen könnte
raise KeyboardInterruptError
mit einemreturn
. Sie müssen nur sicherstellen, dass der Kind-Prozess endet, sobald KeyboardInterrupt empfangen wird. Der Rückgabewert scheint ignoriert zu werden, inmain
noch die KeyboardInterrupt empfangen wird.InformationsquelleAutor Andrey Vlasovskikh
In der Regel diese einfache Struktur funktioniert für Strg-C auf Pool :
Wie gesagt in paar ähnliche Beiträge:
Erfassen keyboardinterrupt in Python ohne versuchen-außer
InformationsquelleAutor igco
Es scheint, es gibt zwei Probleme, Ausnahmen zu machen, während multiprocessing ärgerlich. Die erste (bemerkte Glenn) ist, dass Sie brauchen, um zu verwenden
map_async
mit einem timeout stattmap
um eine sofortige Antwort erhalten (D. H., nicht die Verarbeitung der gesamten Liste). Die zweite (bereits von Andrey) ist das multiprocessing nicht fangen von Ausnahmen, die nicht Erben ausException
(z.B.SystemExit
). Also hier ist meine Lösung, die sich mit beiden:Ich habe nicht bemerkt, jede Leistungseinbuße, aber in meinem Fall die
function
ist ziemlich lang gelebt (Hunderte von Sekunden).Dies ist eigentlich nicht mehr der Fall, zumindest aus meinen Augen und Erfahrung. Wenn Sie fangen die Tastatur Ausnahme in den einzelnen child-Prozesse und fangen es einmal mehr in der main-Prozess, dann können Sie weiterhin mit
map
und alles ist gut.@Linux Cli Aik
eine Lösung bereitgestellt, die unten-das erzeugt dieses Verhalten. Mitmap_async
ist nicht immer erwünscht, wenn der Haupt-thread ist angewiesen auf die Ergebnisse aus der child-Prozesse.InformationsquelleAutor Paul Price
Stimmten die Antwort nicht angehen, der Kern aber eine ähnliche Nebenwirkung.
Jesse Noller, der Autor des multiprocessing-Bibliothek erklärt, wie Sie korrekt mit STRG+C bei der Verwendung
multiprocessing.Pool
in einem alten blog-post.os.setpgrp()
aus in die ZukunftSicher, der einzige Unterschied ist, dass
ProcessPoolExecutor
unterstützt keine Initialisierung-Funktionen. Unter Unix könnten Sie nutzen diefork
Strategie durch deaktivieren der sighandler auf die wichtigsten Verfahren vor dem erstellen der Pool und reaktivieren Sie es anschließend wieder ein. In pebble, ich StilleSIGINT
auf die Kind-Prozesse standardmäßig. Ich bin mir nicht bewusst der Grund, warum Sie das nicht tun das gleiche mit dem Python-Pools. Am Ende konnte der Benutzer re-legen Sie dieSIGINT
- handler, falls er/Sie will, verletzt sich selbst.Diese Lösung scheint zu verhindern, dass Strg-C unterbrechen, der wichtigste Prozess als gut.
Ich habe gerade getestet auf Python 3.5 und es funktioniert, welche version von Python benutzt du? Was OS?
InformationsquelleAutor noxdafox
Fand ich, für die Zeit, die beste Lösung ist nicht zu verwenden, die multiprocessing.pool Funktion, sondern Rollen Sie Ihre eigenen pool-Funktionalität. Ich ein Beispiel, das die Fehler mit apply_async sowie ein Beispiel zeigt, wie Sie zu vermeiden, mit der pool-Funktionalität insgesamt.
http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/
Ich habe nicht bemerkt, jede Leistung, eine Strafe mit einem timeout, obwohl ich schon mit 9999 statt 999999. Die Ausnahme ist, wenn eine Ausnahme, dass die Erben nicht von der Exception-Klasse ausgegeben: dann müssen Sie warten, bis der timeout erreicht wird. Die Lösung, die für alle Ausnahmen abfangen (siehe meine Lösung).
InformationsquelleAutor bboe
Ich bin ein Neuling in Python. Ich suchte überall nach Antworten und stolpern dieser und ein paar anderen blogs und youtube-videos. Ich habe versucht, kopieren und einfügen des Autors obigen code und Schreibe ihn auf meine python 2.7.13 in windows 7 64 - bit. Es ist nah an, was ich will erreichen.
Ich habe meine Kind-Prozesse zu ignorieren, die ControlC und machen den übergeordneten Prozess beenden. Sieht aus wie die Umgehung der Kind-Prozess nicht vermeiden, dieses problem für mich.
Den Teil ab
pool.terminate()
scheint nie zur Ausführung.map_async
auf die user, die ich nicht sonderlich mag. In vielen Situationen, wie bei mir, der Haupt-thread muss warten, bis die einzelnen Prozesse zu beenden. Dies ist einer der Gründe, warummap
vorhanden ist!InformationsquelleAutor Linux Cli Aik
Können Sie versuchen, mit der apply_async Methode, eine Pool-Objekt, wie folgt:
Ausgabe:
Vorteil dieser Methode ist, dass die Ergebnisse verarbeitet, bevor die Unterbrechungen in den Ergebnissen zurückgegeben Wörterbuch:
InformationsquelleAutor bparker856
Seltsam genug, es sieht aus wie Sie haben, um die
KeyboardInterrupt
in der Kinder als gut. Ich hätte erwartet, dass dies funktioniert wie geschrieben... versuchen Sieslowly_square
:Funktionieren sollte, wie erwartet.
das ist OK, aber Sie kann den überblick verlieren-Fehler auftreten. Rücksendung der Fehlermeldung mit stacktrace könnte funktionieren, so dass der übergeordnete Prozess lässt sich sagen, dass ein Fehler aufgetreten ist, aber es immer noch nicht sofort aussteigen, wenn der Fehler Auftritt.
InformationsquelleAutor D.Shawley