Ich versuche ein wenig zu verstehen, was hinter den Kulissen passiert, wenn die Methode apply_sync eines Multiprocessing-Pools verwendet wird.Wer führt den Rückruf aus, wenn die apply_async-Methode eines Multiprocessing-Pools verwendet wird?
Wer führt die Callback-Methode aus? Ist es der Hauptprozess, der apply_async aufgerufen hat?
Angenommen, ich sende eine ganze Reihe von apply_async-Befehlen mit Rückrufen und dann mit meinem Programm fort. Mein Programm macht immer noch Dinge, wenn der Start von apply_async beendet wird. Wie führt der Callback den "Hauptprozess" durch, während der Hauptprozess noch mit dem Skript beschäftigt ist?
Hier ist ein Beispiel.
import multiprocessing
import time
def callback(x):
print '{} running callback with arg {}'.format(multiprocessing.current_process().name, x)
def func(x):
print '{} running func with arg {}'.format(multiprocessing.current_process().name, x)
return x
pool = multiprocessing.Pool()
args = range(20)
for a in args:
pool.apply_async(func, (a,), callback=callback)
print '{} going to sleep for a minute'.format(multiprocessing.current_process().name)
t0 = time.time()
while time.time() - t0 < 60:
pass
print 'Finished with the script'
Der Ausgang ist so etwas wie
PoolWorker-1 läuft func mit ARG 0
PoolWorker-2 ausgeführt func mit ARG 1
PoolWorker-3 Lauf func mit ARG 2
MainProcess geht für eine Minute schlafen < - Hauptprozess ist damit beschäftigt
PoolWorker-4 läuft func mit ARG 3
PoolWorker-1 Lauf func mit ARG 4
PoolWorker-2 ausgeführt func mit ARG 5
PoolWorker-3 func Lauf mit ARG 6
PoolWorker-4 läuft func mit ARG 7
MainProcess Callback-w ith arg 0 < - Hauptprozess läuft Callback, während es noch in der While-Schleife ist !!
MainProcess Callback mit ARG 1
MainProcess Callback mit ARG 2
MainProcess Callback mit ARG 3
MainProcess Callback mit ARG 4
PoolWorker-1 läuft func mit arg 8
...
mit Skript Finished
Wie wird MainProcess den Rückruf läuft, während es in der Mitte dieses while-Schleife ist ??
Es gibt diese Aussage über den Rückruf in der Dokumentation für multiprocessing.Pool, die wie ein Hinweis scheint, aber ich verstehe es nicht.
apply_async (func [, args [, kwds [, Rückruf]]])
Eine Variante des apply() Methode, die ein Ergebnis-Objekt zurückgibt.
Wenn Callback angegeben ist, sollte es eine Callable sein, die ein einzelnes Argument akzeptiert. Wenn das Ergebnis bereit ist, wird ein Rückruf darauf angewendet (sofern der Anruf nicht fehlgeschlagen ist). Der Rückruf sollte sofort abgeschlossen werden, da sonst der Thread, der die Ergebnisse behandelt, blockiert wird.
Danke Dano, dass du dir die Zeit genommen hast, eine so detaillierte Antwort zu schreiben! Wenn ich richtig verstehe, erzeugt der Pool einen * einzigen * neuen Thread (den result_handler), dessen Aufgabe es ist, nur darauf zu warten, dass apply_async beendet wird und dann den Callback im Thread von result_handler aufruft (der Teil des MainProcess ist). Werden die Callbacks (für ein einzelnes Pool-Objekt) sequenziell aufgerufen? I.e. Ein Bündel von apply_async's kann zusammen enden, aber die Callbacks werden nacheinander von result_handler? – Alex
Eine weitere Frage. Was passiert, wenn die Callback-Funktion und das Hauptscript mit denselben Objekten (im MainProcess) verschmutzen? Kann es unvorhersehbares Verhalten geben? I.e. wenn der Callback und etwas später im Hauptskript beide versuchen, in die gleiche Datei zu schreiben oder das gleiche Array zu modifizieren. Wenn der Callback tatsächlich ausgeführt wird, weiß wer, was das Hauptscript zu diesem Zeitpunkt macht. – Alex
@Alex Ja, die Callbacks werden nacheinander ausgeführt.Der '_result_handler'-Thread zieht eine abgeschlossene Task aus der Warteschlange, ruft' _set' (die den Callback ausführt) auf und geht dann zum nächsten über. Aus diesem Grund wird in der Dokumentation darauf hingewiesen, dass der Rückruf sofort abgeschlossen wird. Durch das Ausführen des Rückrufs werden andere Ergebnisse von der Verarbeitung blockiert. – dano