multiprocessing.Pool: ¿Cuándo usar apply, apply_async o map?
No he visto ejemplos claros con casos de uso para Pool.apply , Pool.apply_async y Pool.map . Estoy usando principalmente Pool.map
; ¿Cuáles son las ventajas de los demás?
En los viejos tiempos de Python, para llamar a una función con argumentos arbitrarios, se usaba apply
:
apply(f,args,kwargs)
apply
todavía existe en Python2.7 aunque no en Python3, y generalmente ya no se usa. Hoy en día,
f(*args,**kwargs)
se prefiere. Los multiprocessing.Pool
módulos intentan proporcionar una interfaz similar.
Pool.apply
Es como Python apply
, excepto que la llamada a la función se realiza en un proceso separado. Pool.apply
se bloquea hasta que se completa la función.
Pool.apply_async
También es como el integrado de Python apply
, excepto que la llamada regresa inmediatamente en lugar de esperar el resultado. AsyncResult
Se devuelve un objeto. Llama a su get()
método para recuperar el resultado de la llamada a la función. El get()
método se bloquea hasta que se completa la función. Por tanto, pool.apply(func, args, kwargs)
equivale a pool.apply_async(func, args, kwargs).get()
.
A diferencia de Pool.apply
, el Pool.apply_async
método también tiene una devolución de llamada que, si se proporciona, se llama cuando se completa la función. Esto se puede usar en lugar de llamar get()
.
Por ejemplo:
import multiprocessing as mp
import time
def foo_pool(x):
time.sleep(2)
return x*x
result_list = []
def log_result(result):
# This is called whenever foo_pool(i) returns a result.
# result_list is modified only by the main process, not the pool workers.
result_list.append(result)
def apply_async_with_callback():
pool = mp.Pool()
for i in range(10):
pool.apply_async(foo_pool, args = (i, ), callback = log_result)
pool.close()
pool.join()
print(result_list)
if __name__ == '__main__':
apply_async_with_callback()
puede producir un resultado como
[1, 0, 4, 9, 25, 16, 49, 36, 81, 64]
Tenga en cuenta que, a diferencia de pool.map
, el orden de los resultados puede no corresponderse con el orden en que pool.apply_async
se realizaron las llamadas.
Entonces, si necesita ejecutar una función en un proceso separado, pero desea que el proceso actual se bloquee hasta que esa función regrese, use Pool.apply
. Me gusta Pool.apply
, Pool.map
se bloquea hasta que se devuelve el resultado completo.
Si desea que el grupo de procesos de trabajo realice muchas llamadas a funciones de forma asincrónica, utilice Pool.apply_async
. No se garantiza que el orden de los resultados sea el mismo que el orden de las llamadas a Pool.apply_async
.
Tenga en cuenta también que puede llamar a varias funciones diferentesPool.apply_async
(no todas las llamadas necesitan usar la misma función).
Por el contrario, Pool.map
aplica la misma función a muchos argumentos. Sin embargo, a diferencia de Pool.apply_async
, los resultados se devuelven en el orden correspondiente al orden de los argumentos.
A continuación se ofrece una descripción general en formato de tabla para mostrar las diferencias entre Pool.apply
, y . Al elegir uno, debes tener en cuenta los argumentos múltiples, la concurrencia, el bloqueo y el orden:Pool.apply_async
Pool.map
Pool.map_async
| Multi-args Concurrence Blocking Ordered-results
---------------------------------------------------------------------
Pool.map | no yes yes yes
Pool.map_async | no yes no yes
Pool.apply | yes no yes no
Pool.apply_async | yes yes no no
Pool.starmap | yes yes yes yes
Pool.starmap_async| yes yes no no
Notas:
Pool.imap
yPool.imap_async
– versión más lenta de map y map_async.Pool.starmap
método, muy similar al método map además de la aceptación de múltiples argumentos.Async
Los métodos envían todos los procesos a la vez y recuperan los resultados una vez finalizados. Utilice el método get para obtener los resultados.Pool.map
(oPool.apply
) los métodos son muy similares al mapa integrado de Python (o aplicar). Bloquean el proceso principal hasta que todos los procesos se completan y devuelven el resultado.
Ejemplos:
mapa
Se llama para una lista de trabajos a la vez.
results = pool.map(func, [1, 2, 3])
aplicar
Sólo se le puede llamar para un trabajo.
for x, y in [[1, 1], [2, 2]]:
results.append(pool.apply(func, (x, y)))
def collect_result(result):
results.append(result)
mapa_async
Se llama para una lista de trabajos a la vez.
pool.map_async(func, jobs, callback=collect_result)
aplicar_async
Solo se puede llamar para un trabajo y ejecuta un trabajo en segundo plano en paralelo
for x, y in [[1, 1], [2, 2]]:
pool.apply_async(worker, (x, y), callback=collect_result)
mapa estelar
Es una variante de pool.map
la cual soporta múltiples argumentos.
pool.starmap(func, [(1, 1), (2, 1), (3, 1)])
mapa estelar_async
Una combinación de starmap() y map_async() que itera sobre iterables de iterables y llama a func con los iterables desempaquetados. Devuelve un objeto de resultado.
pool.starmap_async(calculate_worker, [(1, 1), (2, 1), (3, 1)], callback=collect_result)
Referencia:
Encuentre la documentación completa aquí: https://docs.python.org/3/library/multiprocessing.html