Wie kann ich mit KeyboardInterrupt-Ereignissen mit den Multiprocessing-Pools von Python umgehen? 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()
Wenn KeyboardInterrupt
ich den obigen Code ausführe, wird der beim Drücken ausgelöst ^C
, aber der Prozess hängt einfach an diesem Punkt und ich muss ihn extern beenden.
Ich möchte jederzeit drücken ^C
können und alle Prozesse ordnungsgemäß beenden.
python
multiprocessing
pool
keyboardinterrupt
Fragsworth
quelle
quelle
Antworten:
Dies ist ein Python-Fehler. Beim Warten auf eine Bedingung in threading.Condition.wait () wird KeyboardInterrupt niemals gesendet. Repro:
Die KeyboardInterrupt-Ausnahme wird erst ausgeliefert, wenn wait () zurückgegeben wird, und sie wird nie zurückgegeben, sodass der Interrupt niemals auftritt. KeyboardInterrupt sollte mit ziemlicher Sicherheit eine Wartezeit unterbrechen.
Beachten Sie, dass dies nicht der Fall ist, wenn eine Zeitüberschreitung angegeben wird. cond.wait (1) erhält den Interrupt sofort. Eine Problemumgehung besteht darin, ein Zeitlimit anzugeben. Ersetzen Sie dazu
mit
o.ä.
quelle
Nach dem, was ich kürzlich gefunden habe, besteht die beste Lösung darin, die Arbeitsprozesse so einzurichten, dass SIGINT vollständig ignoriert wird, und den gesamten Bereinigungscode auf den übergeordneten Prozess zu beschränken. Dies behebt das Problem sowohl für inaktive als auch für ausgelastete Arbeitsprozesse und erfordert keinen Fehlerbehandlungscode in Ihren untergeordneten Prozessen.
Erläuterungen und den vollständigen Beispielcode finden Sie unter http://noswap.com/blog/python-multiprocessing-keyboardinterrupt/ bzw. http://github.com/jreese/multiprocessing-keyboardinterrupt .
quelle
time.sleep(10)
im Hauptprozess. Wenn Sie diesen Ruhezustand entfernen oder warten, bis der Prozess versucht, sich dem Pool anzuschließen, was Sie tun müssen, um sicherzustellen, dass die Jobs abgeschlossen sind, leiden Sie immer noch unter demselben Problem, das der Hauptprozess nicht hat Empfangen Sie den KeyboardInterrupt nicht, während er auf den Abfragevorgang wartetjoin
.pool.terminate()
nie , wird also nie ausgeführt. Wenn die Kinder das Signal ignorieren, wird nichts erreicht. @ Glenns Antwort löst das Problem..join()
nur bei Unterbrechung aufgerufen. Es überprüft einfach manuell das Ergebnis der.apply_async()
Verwendung,AsyncResult.ready()
um festzustellen, ob es bereit ist, was bedeutet, dass wir sauber fertig sind.Aus bestimmten Gründen werden nur von der Basisklasse geerbte Ausnahmen
Exception
normal behandelt. Als Abhilfe können , können Sie Ihre re-raisenKeyboardInterrupt
alsException
Beispiel:Normalerweise erhalten Sie die folgende Ausgabe:
Wenn Sie also treffen
^C
, erhalten Sie:quelle
KeyboardInterrupt
ankommt, währendmultiprocessing
es seinen eigenen IPC-Datenaustausch durchführt,try..catch
wird das (offensichtlich) nicht aktiviert.raise KeyboardInterruptError
ein ersetzenreturn
. Sie müssen nur sicherstellen, dass der untergeordnete Prozess beendet wird, sobald KeyboardInterrupt empfangen wird. Der Rückgabewert scheint ignoriert zu werden,main
dennoch wird der KeyboardInterrupt empfangen.Normalerweise funktioniert diese einfache Struktur für Ctrl- Con Pool:
Wie in einigen ähnlichen Beiträgen angegeben:
Erfassen Sie Tastaturinterrupts in Python ohne Try-Except
quelle
Die abgestimmte Antwort befasst sich nicht mit dem Kernproblem, sondern mit einem ähnlichen Nebeneffekt.
Jesse Noller, der Autor der Multiprocessing-Bibliothek, erklärt, wie man
multiprocessing.Pool
in einem alten Blog-Beitrag richtig mit STRG + C umgeht .quelle
os.setpgrp()
aus der Zukunft herausProcessPoolExecutor
Initialisierungsfunktionen nicht unterstützt werden. Unter Unix können Sie diefork
Strategie nutzen, indem Sie den Sighandler für den Hauptprozess deaktivieren, bevor Sie den Pool erstellen und anschließend wieder aktivieren. In Pebble schweige ichSIGINT
standardmäßig zu den untergeordneten Prozessen. Mir ist nicht bekannt, warum sie mit den Python-Pools nicht dasselbe tun. Am Ende könnte der Benutzer denSIGINT
Handler zurücksetzen, falls er sich selbst verletzen möchte.Es scheint, dass es zwei Probleme gibt, die Ausnahmen bei der Mehrfachverarbeitung nerven. Die erste (von Glenn notierte) ist, dass Sie
map_async
eine Zeitüberschreitung verwendenmap
müssen, um eine sofortige Antwort zu erhalten (dh die Verarbeitung der gesamten Liste nicht abzuschließen). Die zweite (von Andrey notierte) ist, dass Multiprocessing keine Ausnahmen abfängt, die nicht vonException
(zSystemExit
. B. ) erben . Hier ist meine Lösung, die sich mit beiden befasst:quelle
function
ist die ziemlich langlebig (Hunderte von Sekunden).map
und alles ist in Ordnung.@Linux Cli Aik
hat unten eine Lösung bereitgestellt, die dieses Verhalten erzeugt. Die Verwendungmap_async
ist nicht immer erwünscht, wenn der Hauptthread von den Ergebnissen der untergeordneten Prozesse abhängt.Ich fand vorerst, dass die beste Lösung darin besteht, nicht die Funktion multiprocessing.pool zu verwenden, sondern Ihre eigene Poolfunktionalität zu erweitern. Ich habe ein Beispiel bereitgestellt, das den Fehler mit apply_async demonstriert, sowie ein Beispiel, das zeigt, wie die Poolfunktionalität insgesamt vermieden werden kann.
http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/
quelle
Ich bin ein Neuling in Python. Ich habe überall nach Antworten gesucht und bin auf diesen und einige andere Blogs und Youtube-Videos gestoßen. Ich habe versucht, den obigen Code des Autors zu kopieren, einzufügen und auf meinem Python 2.7.13 in Windows 7 64-Bit zu reproduzieren. Es ist nah an dem, was ich erreichen möchte.
Ich habe meine untergeordneten Prozesse dazu gebracht, die ControlC zu ignorieren und den übergeordneten Prozess zu beenden. Es sieht so aus, als würde das Umgehen des untergeordneten Prozesses dieses Problem für mich vermeiden.
Der Teil, der bei beginnt,
pool.terminate()
scheint nie ausgeführt zu werden.quelle
map_async
auf den Benutzer, was mir nicht besonders gefällt. In vielen Situationen wie meiner muss der Haupt-Thread warten, bis die einzelnen Prozesse abgeschlossen sind. Dies ist einer der Gründe, warum esmap
existiert!Sie können versuchen, die Methode apply_async eines Pool-Objekts wie folgt zu verwenden:
Ausgabe:
Ein Vorteil dieser Methode besteht darin, dass Ergebnisse, die vor der Unterbrechung verarbeitet wurden, im Ergebniswörterbuch zurückgegeben werden:
quelle
Seltsamerweise sieht es so aus, als müsste man auch mit
KeyboardInterrupt
den Kindern umgehen . Ich hätte erwartet, dass dies wie geschrieben funktioniert ... versuchen Sie esslowly_square
mit:Das sollte wie erwartet funktionieren.
quelle