multiprocessing.Pool
ya tiene una cola de resultados compartida, no es necesario involucrar adicionalmente a Manager.Queue
. Manager.Queue
es una queue.Queue
(cola de subprocesos múltiples) debajo del capó, ubicada en un proceso de servidor separado y expuesta a través de proxies. Esto agrega una sobrecarga adicional en comparación con la cola interna de Pool. Contrariamente a confiar en el manejo de resultados nativo de Pool, Manager.Queue
no se garantiza que los resultados en el también estén ordenados.
Los procesos de trabajo no se inician con .apply_async()
, esto ya sucede cuando crea una instancia Pool
. Lo que se inicia cuando llamas pool.apply_async()
es un nuevo "trabajo". Los procesos de trabajo de Pool ejecutan la multiprocessing.pool.worker
función bajo el capó. Esta función se encarga de procesar las nuevas "tareas" transferidas a través del interno de Pool Pool._inqueue
y de enviar los resultados al padre a través del Pool._outqueue
. Su especificado func
se ejecutará dentro multiprocessing.pool.worker
. func
solo tiene que hacer return
algo y el resultado se enviará automáticamente al padre.
.apply_async()
Inmediatamente (asincrónicamente) devuelve un AsyncResult
objeto (alias de ApplyResult
). Necesita llamar .get()
(está bloqueando) en ese objeto para recibir el resultado real. Otra opción sería registrar una función de devolución de llamada , que se activa tan pronto como el resultado esté listo.
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}')
Salida de ejemplo:
<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 el timeout
parámetro -para .get()
no detendrá el procesamiento real de la tarea dentro del trabajador, solo desbloquea al padre en espera al generar un multiprocessing.TimeoutError
.