2014-10-23 7 views
93

Ich versuche zu lernen, wie Pythons multiprocessing-Paket zu verwenden, aber ich verstehe nicht den Unterschied zwischen map_async und imap. Ich habe festgestellt, dass sowohl map_async als auch imap asynchron ausgeführt werden. Wann sollte ich eins über das andere benutzen? Und wie soll ich das von map_async zurückgegebene Ergebnis abrufen?multiprocessing.Pool: Was ist der Unterschied zwischen map_async und imap?

Sollte 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 

Antwort

264

Es gibt zwei wesentliche Unterschiede zwischen imap/imap_unordered und map/map_async:

  1. Die Art, wie sie verbrauchen die iterable Sie an sie weitergeben.
  2. Die Art, wie sie das Ergebnis zurück zu Ihnen zurückgeben.

map verbraucht Ihr iterable durch die iterable in eine Liste konvertieren (vorausgesetzt, es ist keine Liste bereits ist), sie in Stücke brechen und in der Pool diese Brocken auf die Arbeitsprozesse zu senden. Das Iterable in Chunks zu zerlegen, ist besser, als jedes Element im Iterable zwischen den einzelnen Prozessen einzeln zu übergeben - insbesondere, wenn das Iterable groß ist. Das Iterable in eine Liste umzuwandeln, um es zu chunken, kann jedoch sehr hohe Speicherkosten haben, da die gesamte Liste im Speicher gehalten werden muss.

imap nicht das iterable Sie es in eine Liste, noch bricht es in Stücke (standardmäßig). Es wird über das iterierbare Element einzeln iterieren und sie jeweils an einen Arbeitsprozess senden. Dies bedeutet, dass Sie nicht den Memory-Hit des Konvertierens des gesamten Iterablen in eine Liste verwenden, aber es bedeutet auch, dass die Leistung für große Iterables langsamer ist, weil Chunking fehlt. Dies kann gemildert werden, indem ein chunksize-Argument, das größer als der Standardwert von 1 ist, übergeben wird.

Der andere große Unterschied zwischen imap/imap_unordered und map/map_async, ist, dass mit imap/imap_unordered, Sie Ergebnisse von Arbeitern empfangen, so bald beginnen können, wie sie bereit sind, anstatt für alle von ihnen zu warten zu sein fertig. Mit map_async wird ein AsyncResult sofort zurückgegeben, aber man kann nicht wirklich abrufen Ergebnisse von diesem Objekt, bis alle von ihnen verarbeitet worden sind, an welchen Stellen sie die gleiche Liste zurückgibt, dass map tut (map tatsächlich intern als map_async(...).get() implementiert). Es gibt keine Möglichkeit, Teilergebnisse zu erhalten. Sie haben entweder das gesamte Ergebnis oder nichts.

imap und imap_unordered beide Iterables sofort zurückgeben. Mit imap werden die Ergebnisse vom iterablen Wert zurückgegeben, sobald sie fertig sind, während die Reihenfolge der Eingabe iterierbar bleibt. Mit imap_unordered werden Ergebnisse geliefert, sobald sie fertig sind, unabhängig von der Reihenfolge der Eingabe iterierbar.Also, sagen Sie dies haben:

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))) 

erhalten Sie folgende Ausgabe:

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

Wenn Sie p.imap_unordered statt p.imap verwenden, werden Sie sehen:

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

Wenn Sie p.map oder p.map_async().get(), Sie werden sehen:

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

die primären Gründe also, imap/imap_unordered über map_async zu verwenden sind:

  1. Ihre iterable groß genug ist, dass es in eine Liste konvertieren würde dazu führen Sie aus/verwenden zu viel Speicher laufen.
  2. Sie möchten mit der Verarbeitung der Ergebnisse beginnen können, bevor von ihnen abgeschlossen sind.
+1

was ist mit apply und apply_async? –

+6

@HarshDaftary 'apply' sendet eine einzelne Aufgabe an einen Worker-Prozess und blockiert dann bis zum Abschluss. 'apply_async' sendet eine einzelne Aufgabe an einen Arbeitsprozess und gibt dann sofort ein' AsyncResult'-Objekt zurück, mit dem auf den Abschluss der Aufgabe gewartet und das Ergebnis abgerufen werden kann. 'apply' wird durch Aufruf von' apply_async (...). get() 'implementiert. – dano

+0

@dano Ist es möglich, den Code so zu ändern, dass auch die in Kommentaren enthaltenen Sekunden gedruckt werden? Vielen Dank. –

Verwandte Themen