Esistono due differenze chiave tra imap
/ imap_unordered
e map
/ map_async
:
- Il modo in cui consumano l'iterabile che passi a loro.
- Il modo in cui ti restituiscono il risultato.
map
consuma il tuo iterabile convertendo l'iterabile in un elenco (supponendo che non sia già un elenco), suddividendolo in blocchi e inviando quei blocchi ai processi di lavoro in Pool
. La suddivisione dell'iterabile in blocchi ha prestazioni migliori rispetto al passaggio di ciascun elemento nell'iterabile tra i processi un elemento alla volta, in particolare se l'iterabile è grande. Tuttavia, trasformando l'iterabile in un elenco per ridurlo, può avere un costo di memoria molto elevato, poiché l'intero elenco dovrà essere tenuto in memoria.
imap
non trasforma l'iterabile che lo dai in un elenco, né lo divide in blocchi (per impostazione predefinita). Esaminerà l'iterabile un elemento alla volta e li invierà a un processo di lavoro. Ciò significa che non si prende il colpo di memoria del convertire l'intero iterabile in un elenco, ma significa anche che le prestazioni sono più lente per i grandi iterabili, a causa della mancanza di blocchi. Questo può essere mitigato passando un chunksize
argomento più grande del valore predefinito di 1, tuttavia.
L'altra grande differenza tra imap
/ imap_unordered
e map
/ map_async
, è che con imap
/ imap_unordered
, puoi iniziare a ricevere risultati dai lavoratori non appena sono pronti, piuttosto che dover aspettare che finiscano tutti. Con map_async
, AsyncResult
viene immediatamente restituito un, ma non è possibile effettivamente recuperare i risultati da quell'oggetto fino a quando non sono stati elaborati tutti, a quel punto restituisce lo stesso elenco che map
viene ( map
effettivamente implementato internamente come map_async(...).get()
). Non c'è modo di ottenere risultati parziali; o hai l'intero risultato o niente.
imap
ed imap_unordered
entrambi restituiscono subito iterabili. Con imap
, i risultati saranno ottenuti dall'iterabile non appena saranno pronti, pur mantenendo l'ordinamento dell'input iterabile. Con imap_unordered
, i risultati saranno prodotti non appena saranno pronti, indipendentemente dall'ordine dell'input iterabile. Quindi, supponiamo di avere questo:
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)))
Questo produrrà:
3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Se usi p.imap_unordered
invece di p.imap
, vedrai:
3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)
Se usi p.map
o p.map_async().get()
, vedrai:
3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Quindi, i motivi principali per utilizzare imap
/ imap_unordered
sopra map_async
sono:
- Il tuo iterabile è abbastanza grande che la conversione in un elenco potrebbe farti esaurire / utilizzare troppa memoria.
- Si vuole essere in grado di avviare l'elaborazione i risultati prima di tutto di loro sono stati completati.