Hay dos diferencias clave entre imap/ imap_unorderedy map/ map_async:
- La forma en que consumen lo iterable que les pasa.
- La forma en que te devuelven el resultado.
mapconsume tu iterable convirtiéndolo en una lista (suponiendo que ya no sea una lista), dividiéndolo en trozos y enviando esos trozos a los procesos de trabajo en el Pool. Romper el iterable en trozos funciona mejor que pasar cada elemento en el iterable entre procesos, un elemento a la vez, particularmente si el iterable es grande. Sin embargo, convertir el iterable en una lista para fragmentarlo puede tener un costo de memoria muy alto, ya que toda la lista deberá mantenerse en la memoria.
imapno convierte el iterable que le da en una lista, ni lo divide en trozos (por defecto). Iterará sobre el elemento iterable de uno en uno y los enviará a un proceso de trabajo. Esto significa que no tiene el golpe de memoria de convertir todo el iterable en una lista, pero también significa que el rendimiento es más lento para iterables grandes, debido a la falta de fragmentación. chunksizeSin embargo, esto puede mitigarse pasando un argumento mayor que el predeterminado de 1.
La otra gran diferencia entre imap/ imap_unorderedy map/ map_asynces que con imap/ imap_unordered, puede comenzar a recibir resultados de los trabajadores tan pronto como estén listos, en lugar de tener que esperar a que todos terminen. Con map_async, AsyncResultse devuelve de inmediato, pero en realidad no puede recuperar resultados de ese objeto hasta que todos hayan sido procesados, en cuyo momento devuelve la misma lista que mapsí (en maprealidad se implementa internamente como map_async(...).get()). No hay forma de obtener resultados parciales; tienes el resultado completo o nada.
imapy imap_unorderedambos devuelven iterables de inmediato. Con imap, los resultados se obtendrán del iterable tan pronto como estén listos, mientras se conserva el orden del iterable de entrada. Con imap_unordered, los resultados se producirán tan pronto como estén listos, independientemente del orden de la entrada iterable. Entonces, digamos que tienes esto:
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)))
Esto generará:
3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Si usa en p.imap_unorderedlugar de p.imap, verá:
3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)
Si usa p.mapo p.map_async().get(), verá:
3 (Time elapsed: 5s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Entonces, las razones principales para usar imap/ imap_unorderedover map_asyncson:
- Su iterable es lo suficientemente grande como para que convertirlo en una lista le haga quedarse / usar demasiada memoria.
- ¿Quieres ser capaz de iniciar el procesamiento de los resultados antes de todo de ellos se han completado.
applyenvía una única tarea a un proceso de trabajo y luego bloquea hasta que se completa.apply_asyncenvía una única tarea a un proceso de trabajo y luego devuelve inmediatamente unAsyncResultobjeto, que puede usarse para esperar a que la tarea finalice y recuperar el resultado.applyse implementa simplemente llamandoapply_async(...).get()Pooldocumentación oficial en lugar de la aburrida existente .