Python: multiprocessing.anzeigen: Wenn ein Prozess eine Ausnahme auslöst, warum sind nicht andere Prozesse' finally-Blöcke genannt?
Mein Verständnis ist, dass endlich Klauseln muss *immer* ausgeführt werden, wenn die versuchen, eingegeben wurde.
import random
from multiprocessing import Pool
from time import sleep
def Process(x):
try:
print x
sleep(random.random())
raise Exception('Exception: ' + x)
finally:
print 'Finally: ' + x
Pool(3).map(Process, ['1','2','3'])
Erwartete Ausgabe ist, dass für jedes x welches gedruckt wird, auf seine eigene, indem Sie die Linie 8, es muss werden, ein vorkommen von 'Endlich x'.
Beispiel-Ausgabe:
$ python bug.py
1
2
3
Finally: 2
Traceback (most recent call last):
File "bug.py", line 14, in <module>
Pool(3).map(Process, ['1','2','3'])
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 225, in map
return self.map_async(func, iterable, chunksize).get()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 522, in get
raise self._value
Exception: Exception: 2
Scheint es, dass eine Ausnahme die Beendigung eines Prozesses beendet die Eltern und Geschwister Prozesse, auch wenn es weitere Arbeit erforderlich zu tun, die in anderen Prozessen.
Warum bin ich da falsch? Warum ist dies richtig? Wenn dies korrekt ist, wie sollte man sicher bereinigen von Ressourcen, die in Multiprozess-Python?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Kurze Antwort:
SIGTERM
Trumpffinally
.Lange Antwort: Aktivieren Sie die Protokollierung mit
mp.log_to_stderr()
:Die logging-Ausgabe enthält:
Entspricht diesen code in
multiprocessing.pool._terminate_pool
:Jeder
p
impool
ist einmultiprocessing.Process
und die Berufungterminate
(zumindest auf nicht-Windows-Rechner) ruft SIGTERM:vom
multiprocessing/forking.py
:So kommt es zu dem, was passiert, wenn ein Python-Prozess in einem
try
suite gesendetSIGTERM
.Betrachten Sie das folgende Beispiel (test.py):
Wenn Sie es ausführen, dann senden Sie eine
SIGTERM
, dann endet der Prozess sofort, ohne Eingabe derfinally
suite, wie gezeigt, indem Sie keine Ausgabe und keine Verzögerung.In einem terminal:
Im zweiten terminal:
Ergebnis im ersten terminal:
Vergleichen Sie das mit, was passiert, wenn der Prozess gesendet wird, eine
SIGINT
(C-c
):Im zweiten terminal:
Ergebnis im ersten terminal:
Fazit:
SIGTERM
Trumpffinally
.Den Antwort von unutbu definitiv erklärt warum Sie erhalten das Verhalten, das Sie beobachten. Es sollte jedoch betont werden, dass SIGTERM gesendet wird, nur weil, wie
multiprocessing.pool._terminate_pool
umgesetzt wird. Wenn Sie können vermeiden Sie die VerwendungPool
, dann können Sie die Verhalten, die Sie wünschen. Hier ist ein entlehnt Beispiel:Nach dem senden eines SIGINT ist, Beispiel Ausgabe:
Beachten Sie, dass die
finally
Klausel lief für alle Prozesse. Wenn Sie brauchen, shared memory, sollten Sie die VerwendungQueue
,Pipe
,Manager
oder externen speichern wieredis
odersqlite3
.finally
wieder stellt sich die ursprüngliche Ausnahme es sei denn, Siereturn
aus es. Die Ausnahme wird dann angehoben, durchPool.map
und tötet die gesamte Anwendung. Die Teilprozesse beendet sind, und Sie sehen keine anderen Ausnahmen.Können Sie ein
return
zu schlucken Ausnahme:Dann sollten Sie
None
in Ihremmap
Ergebnis, wenn eine Ausnahme aufgetreten ist.Pool.map
nachempfunden istmap
, das endet auch, wenn die Funktion zugeordnet, wirft eine exception. Vielleicht (ausprobieren) die Kind-Prozesse beendet sind, normalerweise und tatsächlich führen diefinally
- nur weil dein main-thread getötet wird zuerst der Ausgang von den Kindern nicht mehr Lesen.