multiprocessing.Poolya tiene una cola de resultados compartida, no es necesario involucrar adicionalmente a Manager.Queue. Manager.Queuees 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.Queueno 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.workerfunción bajo el capó. Esta función se encarga de procesar las nuevas "tareas" transferidas a través del interno de Pool Pool._inqueuey de enviar los resultados al padre a través del Pool._outqueue. Su especificado funcse ejecutará dentro multiprocessing.pool.worker. funcsolo tiene que hacer returnalgo y el resultado se enviará automáticamente al padre.
.apply_async() Inmediatamente (asincrónicamente) devuelve un AsyncResultobjeto (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 timeoutpará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.