multiprocessing.Pool: ¿Cuándo usar apply, apply_async o map?

Resuelto Phyo Arkar Lwin asked hace 12 años • 3 respuestas

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?

Phyo Arkar Lwin avatar Dec 16 '11 18:12 Phyo Arkar Lwin
Aceptado

En los viejos tiempos de Python, para llamar a una función con argumentos arbitrarios, se usaba apply:

apply(f,args,kwargs)

applytodaví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.Poolmódulos intentan proporcionar una interfaz similar.

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

Pool.apply_asyncTambién es como el integrado de Python apply, excepto que la llamada regresa inmediatamente en lugar de esperar el resultado. AsyncResultSe 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_asyncmé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_asyncse 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.mapse 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.mapaplica 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.

unutbu avatar Dec 16 '2011 11:12 unutbu

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_asyncPool.mapPool.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.imapy Pool.imap_async– versión más lenta de map y map_async.

  • Pool.starmapmétodo, muy similar al método map además de la aceptación de múltiples argumentos.

  • AsyncLos 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(o Pool.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.mapla 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

Rene B. avatar Jan 09 '2020 12:01 Rene B.