multiprocessing.Pool
já tem uma fila de resultados compartilhada, não há necessidade de envolver adicionalmente a Manager.Queue
. Manager.Queue
é uma queue.Queue
(fila de multithreading) sob o capô, localizada em um processo de servidor separado e exposta por meio de proxies. Isso adiciona sobrecarga em comparação com a fila interna do Pool. Ao contrário de confiar no tratamento de resultados nativo do Pool, os resultados no Manager.Queue
também não têm garantia de serem solicitados.
Os processos de trabalho não são iniciados com .apply_async()
, isso já acontece quando você instancia Pool
. O que é iniciado quando você liga pool.apply_async()
é um novo "trabalho". Os processos de trabalho do Pool executam a multiprocessing.pool.worker
função sob o capô. Esta função se encarrega de processar novas "tarefas" transferidas por meio do pool interno Pool._inqueue
e de enviar os resultados de volta ao pai pelo Pool._outqueue
. Seu especificado func
será executado em multiprocessing.pool.worker
. func
só precisa de return
algo e o resultado será automaticamente enviado de volta para o pai.
.apply_async()
imediatamente (de forma assíncrona) retorna um AsyncResult
objeto (alias para ApplyResult
). Você precisa chamar .get()
(está bloqueando) naquele objeto para receber o resultado real. Outra opção seria registrar uma função de retorno de chamada , que é acionada assim que o resultado fica pronto.
from multiprocessing import Pool
def busy_foo(i):
"""Dummy function simulating cpu-bound work."""
for _ in range(int(10e6)): # do stuff
pass
return i
if __name__ == '__main__':
with Pool(4) as pool:
print(pool._outqueue) # DEMO
results = [pool.apply_async(busy_foo, (i,)) for i in range(10)]
# `.apply_async()` immediately returns AsyncResult (ApplyResult) object
print(results[0]) # DEMO
results = [res.get() for res in results]
print(f'result: {results}')
Exemplo de saída:
<multiprocessing.queues.SimpleQueue object at 0x7fa124fd67f0>
<multiprocessing.pool.ApplyResult object at 0x7fa12586da20>
result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Nota: Especificar o timeout
parâmetro -para .get()
não interromperá o processamento real da tarefa dentro do trabalhador, apenas desbloqueia o pai em espera levantando a multiprocessing.TimeoutError
.