python - lock - multiprocesamiento.Pool: ¿Cuál es la diferencia entre map_async y imap?
python pool apply_async (1)
Estoy tratando de aprender a usar el paquete de multiprocessing
de Python, pero no entiendo la diferencia entre map_async
y imap
. Noté que tanto map_async
como imap
se ejecutan de forma asíncrona. Entonces, ¿cuándo debería usar uno sobre el otro? ¿Y cómo debo recuperar el resultado devuelto por map_async
?
¿Debería usar algo como esto?
def test():
result = pool.map_async()
pool.close()
pool.join()
return result.get()
result=test()
for i in result:
print i
Hay dos diferencias clave entre imap
/ imap_unordered
y map
/ map_async
:
- La forma en que consumen el iterable les pasas.
- La forma en que devuelven el resultado a usted.
map
consume su iterable convirtiendo el iterable en una lista (asumiendo que ya no es una lista), dividiéndolo en fragmentos y enviando esos fragmentos a los procesos de trabajo en el Pool
. Al dividir el iterable en fragmentos se realiza mejor que pasando cada elemento en el iterable entre los procesos de un elemento a la vez, particularmente si el iterable es grande. Sin embargo, convertir el iterable en una lista para dividirlo puede tener un costo de memoria muy alto, ya que toda la lista deberá mantenerse en la memoria.
imap
no convierte el iterable que le das en una lista, ni lo divide en fragmentos (por defecto). Se repetirá sobre el elemento iterable de uno en uno, y se los enviará a cada uno a un proceso de trabajo. Esto significa que no se toma el golpe de memoria de convertir todo el iterable en una lista, sino que también significa que el rendimiento es más lento para los iterables grandes, debido a la falta de fragmentación. Sin embargo, esto se puede mitigar pasando un argumento chunksize
mayor que el predeterminado de 1.
La otra gran diferencia entre imap
/ imap_unordered
y map
/ map_async
es 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
, se devuelve un AsyncResult
inmediato, pero no se pueden recuperar los resultados de ese objeto hasta que todos hayan sido procesados, en cuyo caso se devuelve la misma lista que el map
(el map
se implementa internamente como map_async(...).get()
). No hay forma de obtener resultados parciales; o tienes el resultado completo, o nada.
imap
y imap_unordered
devuelven iterables de inmediato. Con imap
, los resultados se obtendrán del iterable tan pronto como estén listos, mientras se preserva el orden de la entrada iterable. Con imap_unordered
, los resultados se obtendrán tan pronto como estén listos, independientemente del orden de la entrada iterable. Entonces, di 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 dará como resultado:
3 (Time elapsed: 1s)
7 (Time elapsed: 5s)
5 (Time elapsed: 5s)
Si usa p.imap_unordered
lugar de p.imap
, verá:
3 (Time elapsed: 1s)
5 (Time elapsed: 3s)
7 (Time elapsed: 5s)
Si usa p.map
o 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_unordered
sobre map_async
son:
- Su iterable es lo suficientemente grande como para convertirlo a una lista, lo que le causaría la pérdida o el uso de demasiada memoria.
- Desea poder comenzar a procesar los resultados antes de que se completen todos.