it-swarm-pt.tech

multiprocessing.Pool: Quando usar apply, apply_async ou map?

Eu não vi exemplos claros com casos de uso para Pool.apply , Pool.apply_async e Pool.map . Eu estou usando principalmente Pool.map; Quais são as vantagens dos outros?

236
Phyo Arkar Lwin

Nos velhos tempos do Python, para chamar uma função com argumentos arbitrários, você usaria apply:

apply(f,args,kwargs)

apply ainda existe em Python2.7, embora não em Python3, e geralmente não é mais usado. Hoje em dia,

f(*args,**kwargs)

é preferível. Os módulos multiprocessing.Pool tentam fornecer uma interface semelhante.

Pool.apply é como o Python apply, exceto que a chamada de função é executada em um processo separado. Pool.apply bloqueia até que a função esteja concluída.

Pool.apply_async também é como o apply interno do Python, exceto que a chamada retorna imediatamente em vez de esperar pelo resultado. Um objeto AsyncResult é retornado. Você chama seu método get() para recuperar o resultado da chamada de função. O método get() bloqueia até que a função seja concluída. Assim, pool.apply(func, args, kwargs) é equivalente a pool.apply_async(func, args, kwargs).get().

Em contraste com Pool.apply, o método Pool.apply_async também possui um retorno de chamada que, se fornecido, é chamado quando a função é concluída. Isso pode ser usado em vez de chamar get().

Por exemplo:

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 __== '__main__':
    apply_async_with_callback()

pode produzir um resultado como

[1, 0, 4, 9, 25, 16, 49, 36, 81, 64]

Observe que, diferentemente de pool.map, a ordem dos resultados pode não corresponder à ordem em que as chamadas pool.apply_async foram feitas.


Portanto, se você precisar executar uma função em um processo separado, mas quiser que o processo atual seja block até que essa função retorne, use Pool.apply. Como Pool.apply, Pool.map bloqueia até que o resultado completo seja retornado.

Se você quiser que o Pool de processos de trabalho execute muitas chamadas de função de forma assíncrona, use Pool.apply_async. A ordem dos resultados não é garantida para ser o mesmo que a ordem das chamadas para Pool.apply_async.

Observe também que você poderia chamar um número de funções diferentes com Pool.apply_async (nem todas as chamadas precisam usar a mesma função).

Em contraste, Pool.map aplica a mesma função a muitos argumentos. No entanto, ao contrário de Pool.apply_async, os resultados são retornados em uma ordem correspondente à ordem dos argumentos.

351
unutbu

Em relação a apply vs map:

pool.apply(f, args): f é executado apenas em um dos trabalhadores do pool. Então, um dos processos no pool executará f(args).

pool.map(f, iterable): este método divide o iterável em um número de partes que ele envia ao pool de processos como tarefas separadas. Então você aproveita todos os processos no pool.

67
kakhkAtion