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 utilizando 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, usaría apply :

 apply(f,args,kwargs) 

todavía existe la aplicación en Python2.7 aunque no en Python3, y generalmente ya no se usa. Hoy en día,

 f(*args,**kwargs) 

se prefiere. Los módulos multiprocessing.Pool intenta proporcionar una interfaz similar.

Pool.apply es como Python, excepto que la llamada a la función se realiza en un proceso separado. Pool.apply bloquea hasta que se complete la función.

Pool.apply_async también es como la aplicación incorporada de Python, excepto que la llamada se devuelve inmediatamente en lugar de esperar el resultado. Se AsyncResult objeto AsyncResult . Usted llama a su método get() para recuperar el resultado de la llamada a la función. El método get() bloquea hasta que se completa la función. Por lo tanto, pool.apply(func, args, kwargs) es equivalente a pool.apply_async(func, args, kwargs).get() .

A diferencia de Pool.apply , el método Pool.apply_async también tiene una callback que, si se proporciona, se llama cuando la función está completa. Esto se puede utilizar en lugar de llamar a 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 dar un resultado tal 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 se realizaron las llamadas pool.apply_async .


Por lo tanto, 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 . Al igual que Pool.apply , Pool.map bloquea hasta que se devuelve el resultado completo.

Si desea que el Grupo de procesos de trabajo realice muchas llamadas de función de forma asíncrona, use 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 diferentes con Pool.apply_async (no todas las llamadas necesitan usar la misma función).

En contraste, Pool.map aplica la misma función a muchos argumentos. Sin embargo, a diferencia de Pool.apply_async , los resultados se devuelven en un orden correspondiente al orden de los argumentos.

Respecto a apply vs map :

pool.apply(f, args) : f solo se ejecuta en UNO de los trabajadores del pool. Entonces, UNO de los procesos en el grupo ejecutará f(args) .

pool.map(f, iterable) : este método divide el iterable en varios fragmentos que envía al grupo de procesos como tareas separadas. Así que aprovechas todos los procesos en la piscina.