multiprocessing.Pool: Wann wird apply, apply_async oder map verwendet?

Antworten:

424

In den alten Tagen von Python würden Sie Folgendes verwenden, um eine Funktion mit beliebigen Argumenten aufzurufen apply:

apply(f,args,kwargs)

applyexistiert immer noch in Python2.7, jedoch nicht in Python3, und wird im Allgemeinen nicht mehr verwendet. Heutzutage,

f(*args,**kwargs)

Ist bevorzugt. Die multiprocessing.PoolModule versuchen, eine ähnliche Schnittstelle bereitzustellen.

Pool.applyist wie Python apply, nur dass der Funktionsaufruf in einem separaten Prozess ausgeführt wird. Pool.applyblockiert, bis die Funktion abgeschlossen ist.

Pool.apply_asyncist auch wie Pythons integriert apply, außer dass der Aufruf sofort zurückkehrt, anstatt auf das Ergebnis zu warten. Ein AsyncResultObjekt wird zurückgegeben. Sie rufen seine get()Methode auf, um das Ergebnis des Funktionsaufrufs abzurufen. Die get()Methode blockiert, bis die Funktion abgeschlossen ist. Somit pool.apply(func, args, kwargs)ist äquivalent zu pool.apply_async(func, args, kwargs).get().

Im Gegensatz dazu Pool.applyverfügt die Pool.apply_asyncMethode auch über einen Rückruf, der, falls angegeben, nach Abschluss der Funktion aufgerufen wird. Dies kann verwendet werden, anstatt anzurufen get().

Beispielsweise:

import multiprocessing as mp
import time

def foo_pool(x):
    time.sleep(2)
    return x*x

result_list = []
def log_result(result):
    # This is called whenever foo_pool(i) returns a result.
    # result_list is modified only by the main process, not the pool workers.
    result_list.append(result)

def apply_async_with_callback():
    pool = mp.Pool()
    for i in range(10):
        pool.apply_async(foo_pool, args = (i, ), callback = log_result)
    pool.close()
    pool.join()
    print(result_list)

if __name__ == '__main__':
    apply_async_with_callback()

kann ein Ergebnis ergeben wie

[1, 0, 4, 9, 25, 16, 49, 36, 81, 64]

Beachten Sie, dass pool.mapdie Reihenfolge der Ergebnisse möglicherweise nicht der Reihenfolge entspricht, in der die pool.apply_asyncAnrufe getätigt wurden.


Wenn Sie also eine Funktion in einem separaten Prozess ausführen müssen, der aktuelle Prozess jedoch blockiert werden soll, bis diese Funktion zurückkehrt, verwenden Sie Pool.apply. Wie Pool.apply, Pool.mapblockiert , bis das komplette Ergebnis zurückgegeben.

Wenn Sie möchten, dass der Pool von Arbeitsprozessen viele Funktionsaufrufe asynchron ausführt, verwenden Sie Pool.apply_async. Es ist nicht garantiert, dass die Reihenfolge der Ergebnisse mit der Reihenfolge der Aufrufe von übereinstimmt Pool.apply_async.

Beachten Sie auch, dass Sie eine Reihe verschiedener Funktionen mit aufrufen können Pool.apply_async(nicht alle Aufrufe müssen dieselbe Funktion verwenden).

Im Gegensatz dazu wird Pool.mapdieselbe Funktion auf viele Argumente angewendet. Im Gegensatz dazu Pool.apply_asyncwerden die Ergebnisse jedoch in einer Reihenfolge zurückgegeben, die der Reihenfolge der Argumente entspricht.

unutbu
quelle
11
Sollte es if __name__=="__main__"vorher apply_async_with_callback()unter Windows geben?
JFS
3
Vielen Dank. Wie wäre es mit map_async?
Phyo Arkar Lwin
38
Schauen Sie in multiprocessing / pool.py nach und Sie werden sehen, dass dies Pool.map(func,iterable)äquivalent zu ist Pool.map_async(func,iterable).get(). Die Beziehung zwischen Pool.mapund Pool.map_asyncist also ähnlich der von Pool.applyund Pool.apply_async. Die asyncBefehle kehren sofort zurück, während die Nichtbefehle asyncblockieren. Die asyncBefehle haben auch einen Rückruf.
Unutbu
7
Die Entscheidung zwischen Pool.mapund Pool.applyist ähnlich wie die Entscheidung, wann mapoder applyin Python. Sie verwenden nur das Werkzeug, das zum Job passt. Die Entscheidung zwischen der Verwendung der asyncund der Nichtversion asynchängt davon ab, ob der Anruf den aktuellen Prozess blockieren soll und / oder ob Sie den Rückruf verwenden möchten.
Unutbu
6
@falsePockets: Ja. Jeder Aufruf zum apply_asyncZurückgeben eines ApplyResultObjekts. Der Aufruf , dass ApplyResult‚s getMethode wird die zugehörige Funktion Rückgabewert zurückgeben (oder zu erhöhen , mp.TimeoutErrorwenn die Anrufzeiten-out.) Also , wenn Sie den setzen ApplyResults in einer geordneten Liste, dann ihre Aufruf getMethoden werden die Ergebnisse in der gleichen Reihenfolge zurück. Sie können jedoch nur pool.mapin dieser Situation verwenden.
Unutbu
75

In Bezug auf applyvs map:

pool.apply(f, args): fwird nur in EINEM der Arbeiter des Pools ausgeführt. Es wird also EINER der Prozesse im Pool ausgeführt f(args).

pool.map(f, iterable): Diese Methode zerlegt das Iterable in eine Reihe von Blöcken, die es als separate Aufgaben an den Prozesspool sendet. So nutzen Sie alle Prozesse im Pool.

kakhkAtion
quelle
4
Was ist, wenn das iterable ein Generator ist
RustyShackleford
Hmm ... Gute Frage. Um ehrlich zu sein, habe ich noch nie Pools mit Generatoren verwendet, aber dieser Thread könnte hilfreich sein: stackoverflow.com/questions/5318936/…
kakhkAtion
@kakhkAtion Was tun, wenn nur einer der Arbeiter die Funktion ausführt? Was machen die restlichen Arbeiter? Muss ich mich mehrmals bei bewerben bewerben, damit der Rest der Mitarbeiter eine Aufgabe ausführt?
Moondra
3
Wahr. Schauen Sie sich auch pool.apply_async an, wenn Sie Mitarbeiter asynchron zu Mittag essen möchten. "pool_apply blockiert, bis das Ergebnis fertig ist, daher ist apply_async () besser für parallele Arbeiten geeignet"
kakhkAtion
1
Was passiert, wenn ich 4 Prozesse habe, aber apply_async()8 Mal aufgerufen habe ? Wird es automatisch mit einer Warteschlange behandelt?
Saravanabalagi Ramachandran
31

Hier ist eine Übersicht in Tabellenformat , um die Unterschiede zwischen dem zeigen Pool.apply, Pool.apply_async, Pool.mapund Pool.map_async. Bei der Auswahl müssen Sie mehrere Argumente, Parallelität, Blockierung und Bestellung berücksichtigen:

                  | Multi-args   Concurrence    Blocking     Ordered-results
---------------------------------------------------------------------
Pool.map          | no           yes            yes          yes
Pool.map_async    | no           yes            no           yes
Pool.apply        | yes          no             yes          no
Pool.apply_async  | yes          yes            no           no
Pool.starmap      | yes          yes            yes          yes
Pool.starmap_async| yes          yes            no           no

Anmerkungen:

  • Pool.imapund Pool.imap_async- faulere Version von map und map_async.

  • Pool.starmap Methode, die der Map-Methode sehr ähnlich ist, außer dass mehrere Argumente akzeptiert werden.

  • AsyncMethoden senden alle Prozesse auf einmal und rufen die Ergebnisse ab, sobald sie abgeschlossen sind. Verwenden Sie die Methode get, um die Ergebnisse zu erhalten.

  • Pool.map(oder Pool.apply) Methoden sind der in Python integrierten Map (oder Apply) sehr ähnlich. Sie blockieren den Hauptprozess, bis alle Prozesse abgeschlossen sind, und geben das Ergebnis zurück.

Beispiele:

Karte

Wird für eine Liste von Jobs in einer Zeit aufgerufen

results = pool.map(func, [1, 2, 3])

anwenden

Kann nur für einen Job aufgerufen werden

for x, y in [[1, 1], [2, 2]]:
    results.append(pool.apply(func, (x, y)))

def collect_result(result):
    results.append(result)

map_async

Wird für eine Liste von Jobs in einer Zeit aufgerufen

pool.map_async(func, jobs, callback=collect_result)

apply_async

Kann nur für einen Job aufgerufen werden und führt parallel einen Job im Hintergrund aus

for x, y in [[1, 1], [2, 2]]:
    pool.apply_async(worker, (x, y), callback=collect_result)

Sternenkarte

Ist eine Variante, pool.mapdie mehrere Argumente unterstützt

pool.starmap(func, [(1, 1), (2, 1), (3, 1)])

starmap_async

Eine Kombination aus starmap () und map_async (), die über iterable von iterables iteriert und func mit den entpackten iterables aufruft. Gibt ein Ergebnisobjekt zurück.

pool.starmap_async(calculate_worker, [(1, 1), (2, 1), (3, 1)], callback=collect_result)

Referenz:

Die vollständige Dokumentation finden Sie hier: https://docs.python.org/3/library/multiprocessing.html

Rene B.
quelle
2
Pool.starmap () blockiert
Alan Evangelista