multiprocessing.Pool: Was ist der Unterschied zwischen map_async und imap?

182

Ich versuche zu lernen, wie man Pythons multiprocessingPaket benutzt, aber ich verstehe den Unterschied zwischen map_asyncund nicht imap. Mir ist aufgefallen, dass beide map_asyncund imapasynchron ausgeführt werden. Wann sollte ich einen über den anderen verwenden? Und wie soll ich das zurückgegebene Ergebnis abrufen map_async?

Soll ich so etwas verwenden?

def test():
    result = pool.map_async()
    pool.close()
    pool.join()
    return result.get()

result=test()
for i in result:
    print i
Raumfahrt
quelle

Antworten:

490

Es gibt zwei wesentliche Unterschiede zwischen imap/ imap_unorderedund map/ map_async:

  1. Die Art und Weise, wie sie das iterable konsumieren, das Sie an sie weitergeben.
  2. Die Art und Weise, wie sie das Ergebnis an Sie zurücksenden.

mapverbraucht Ihre Iterable, indem Sie die Iterable in eine Liste konvertieren (vorausgesetzt, es ist noch keine Liste), sie in Chunks aufteilen und diese Chunks an die Worker-Prozesse in der senden Pool. Das Aufteilen des Iterables in Blöcke ist besser als das Übergeben jedes Elements im Iterable zwischen Prozessen einzeln - insbesondere, wenn das Iterable groß ist. Das Verwandeln des Iterables in eine Liste, um es zu zerlegen, kann jedoch sehr hohe Speicherkosten verursachen, da die gesamte Liste im Speicher gehalten werden muss.

imapVerwandelt das Iterable, das Sie ihm geben, nicht in eine Liste und zerlegt es auch nicht in Blöcke (standardmäßig). Es wird jeweils ein iterierbares Element durchlaufen und jeweils an einen Arbeitsprozess gesendet. Dies bedeutet, dass Sie nicht den Speicher-Hit der Konvertierung des gesamten iterablen Objekts in eine Liste in Kauf nehmen müssen, aber es bedeutet auch, dass die Leistung bei großen iterierbaren Dateien aufgrund des Mangels an Chunking langsamer ist. Dies kann jedoch durch Übergeben eines chunksizeArguments gemindert werden, das größer als der Standardwert 1 ist.

Der andere große Unterschied zwischen imap/ imap_unorderedund map/ besteht darin map_async, dass Sie mit imap/ imap_unorderedbeginnen können, Ergebnisse von Mitarbeitern zu erhalten, sobald diese bereit sind, anstatt warten zu müssen, bis alle fertig sind. Mit map_asyncwird ein AsyncResultsofort zurückgegeben, aber Sie können die Ergebnisse von diesem Objekt erst dann abrufen, wenn alle verarbeitet wurden. An diesem Punkt wird dieselbe Liste zurückgegeben, die dies maptut ( mapwird tatsächlich intern implementiert als map_async(...).get()). Es gibt keine Möglichkeit, Teilergebnisse zu erzielen. Sie haben entweder das gesamte Ergebnis oder nichts.

imapund imap_unorderedbeide geben sofort iterables zurück. Mit imapwerden die Ergebnisse von der iterierbaren Datei ausgegeben, sobald sie fertig sind, wobei die Reihenfolge der iterierbaren Eingabe beibehalten wird. Mit imap_unorderedwerden die Ergebnisse unabhängig von der Reihenfolge der iterierbaren Eingabe angezeigt, sobald sie fertig sind. Angenommen, Sie haben Folgendes:

import multiprocessing
import time

def func(x):
    time.sleep(x)
    return x + 2

if __name__ == "__main__":    
    p = multiprocessing.Pool()
    start = time.time()
    for x in p.imap(func, [1,5,3]):
        print("{} (Time elapsed: {}s)".format(x, int(time.time() - start)))

Dies wird Folgendes ausgeben:

3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)

Wenn Sie p.imap_unorderedanstelle von verwenden p.imap, sehen Sie:

3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)

Wenn Sie p.mapoder verwenden p.map_async().get(), werden Sie sehen:

3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)

Die Hauptgründe für die Verwendung imap/ imap_unorderedÜber map_asyncsind also:

  1. Ihr Iterable ist groß genug, um bei der Konvertierung in eine Liste zu viel Speicherplatz zu verbrauchen.
  2. Sie möchten in der Lage sein, die Ergebnisse zu verarbeiten, bevor alle abgeschlossen sind.
dano
quelle
1
Was ist mit apply und apply_async?
Harsh Daftary
10
@HarshDaftary applysendet eine einzelne Aufgabe an einen Arbeitsprozess und blockiert sie, bis sie abgeschlossen ist. apply_asyncsendet eine einzelne Aufgabe an einen Arbeitsprozess und gibt dann sofort ein AsyncResultObjekt zurück, mit dem gewartet werden kann, bis die Aufgabe abgeschlossen ist, und das Ergebnis abgerufen wird. applywird durch einfaches Aufrufen vonapply_async(...).get()
dano
50
Das ist die Art von Beschreibung, die eher in der offiziellen PoolDokumentation als in der vorhandenen langweiligen enthalten sein sollte .
Minuten
@dano Ich möchte eine Funktion im Hintergrund ausführen, habe jedoch einige Ressourcenbeschränkungen und kann die Funktion nicht so oft ausführen, wie ich möchte, und möchte die zusätzlichen Ausführungen der Funktion in die Warteschlange stellen. Hast du eine Idee, wie ich das machen soll? Ich habe meine Frage hier . Könnten Sie sich bitte meine Frage ansehen und sehen, ob Sie mir einige Hinweise (oder noch besser eine Antwort) geben können, wie ich das tun soll?
Amir
1
@BallpointBen Sobald es fertig ist, wird mit der nächsten Arbeit fortgefahren. Die Bestellung wird im übergeordneten Prozess ausgeführt.
Dano