En el código de ejemplo a continuación, me gustaría recuperar el valor de retorno de la función worker
. ¿Cómo puedo hacer esto? ¿Dónde se almacena este valor?
Código de ejemplo:
import multiprocessing
def worker(procnum):
'''worker function'''
print str(procnum) + ' represent!'
return procnum
if __name__ == '__main__':
jobs = []
for i in range(5):
p = multiprocessing.Process(target=worker, args=(i,))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
print jobs
Salida:
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[<Process(Process-1, stopped)>, <Process(Process-2, stopped)>, <Process(Process-3, stopped)>, <Process(Process-4, stopped)>, <Process(Process-5, stopped)>]
Parece que no puedo encontrar el atributo relevante en los objetos almacenados jobs
.
multiprocessing.Queue
, en lugar de unManager
aquí. El uso deManager
requiere generar un proceso completamente nuevo, que es excesivo cuandoQueue
lo haría.multiprocessing.Pool.map
para procesar su lista de elementos de trabajo.args=(my_function_argument, )
. Tenga en cuenta la,
coma aquí! De lo contrario, Python se quejará de "argumentos posicionales faltantes". Me tomó 10 minutos entenderlo. Compruebe también el uso manual (en la sección "clase de proceso").Creo que el enfoque sugerido por @sega_sai es el mejor. Pero realmente necesita un ejemplo de código, así que aquí va:
Lo que imprimirá los valores de retorno:
Si está familiarizado con
map
(el Python 2 incorporado) esto no debería ser demasiado desafiante. De lo contrario, eche un vistazo al enlace de sega_Sai .Tenga en cuenta la poca cantidad de código que se necesita. (También tenga en cuenta cómo se reutilizan los procesos).
fuente
getpid()
devolución tiene el mismo valor? Estoy ejecutando Python3pool.map
un rango de 1,000,000 usando más de 10 procesos, veo como máximo dos pids diferentes.pool.apply_async
: docs.python.org/3/library/…Este ejemplo muestra cómo usar una lista de multiprocesamiento. Instancias de tubería para devolver cadenas de un número arbitrario de procesos:
Salida:
Esta solución utiliza menos recursos que un multiprocessing.Queue qué usos
o un multiprocesamiento.SimpleQueue que utiliza
Es muy instructivo mirar la fuente de cada uno de estos tipos.
fuente
Pipe
por proceso frente a unoQueue
para todos los procesos. No sé si eso termina siendo más eficiente en todos los casos.Por alguna razón, no pude encontrar un ejemplo general de cómo hacer esto en
Queue
ningún lugar (incluso los ejemplos de documentos de Python no generan múltiples procesos), así que esto es lo que obtuve trabajando después de 10 intentos:Queue
es una cola de bloqueo segura para subprocesos que puede usar para almacenar los valores de retorno de los procesos secundarios. Por lo tanto, debe pasar la cola a cada proceso. Algo menos obvio aquí es que usted tiene queget()
partir de la cola antes de quejoin
losProcess
es o bien la cola se llena y bloquea todo.Actualización para aquellos que están orientados a objetos (probado en Python 3.4):
fuente
Para cualquier otra persona que esté buscando cómo obtener un valor de un
Process
usoQueue
:fuente
Queue
join()
queue.put(ret)
antes de llamarp.start()
? En ese caso, el subproceso de trabajo se bloqueará paraqueue.get()
siempre. Puede replicar esto copiando mi fragmento de arriba mientras comentaqueue.put(ret)
.queue.get()
tiene que suceder antes de lap.join()
. Funciona ahora para mí.Parece que debería usar la clase multiprocesamiento.Pool en su lugar y usar los métodos .apply () .apply_async (), map ()
http://docs.python.org/library/multiprocessing.html?highlight=pool#multiprocessing.pool.AsyncResult
fuente
Puede usar el
exit
incorporado para establecer el código de salida de un proceso. Se puede obtener delexitcode
atributo del proceso:Salida:
fuente
El paquete de guijarros tiene un buen apalancamiento de abstracción
multiprocessing.Pipe
que lo hace bastante sencillo:Ejemplo de: https://pythonhosted.org/Pebble/#concurrent-decorators
fuente
Pensé que simplificaría los ejemplos más simples copiados desde arriba, trabajando para mí en Py3.6. Más simple es
multiprocessing.Pool
:Puede establecer el número de procesos en la piscina con, por ejemplo,
Pool(processes=5)
. Sin embargo, el valor predeterminado es el recuento de CPU, así que déjelo en blanco para las tareas vinculadas a la CPU. (Las tareas vinculadas a E / S a menudo se adaptan a los subprocesos de todos modos, ya que los subprocesos en su mayoría están esperando, por lo que pueden compartir un núcleo de CPU).Pool
También se aplica la optimización de fragmentación .(Tenga en cuenta que el método de trabajo no se puede anidar dentro de un método. Inicialmente definí mi método de trabajo dentro del método al que hace la llamada
pool.map
, para mantenerlo todo autocontenido, pero luego los procesos no pudieron importarlo, y arrojé "AttributeError : No se puede encurtir el objeto local external_method..inner_method ". Más aquí . Puede estar dentro de una clase.)(Aprecio la impresión original de la pregunta especificada en
'represent!'
lugar de hacerlotime.sleep()
, pero sin ella pensé que algunos códigos se ejecutaban simultáneamente cuando no era así).Py3
ProcessPoolExecutor
también tiene dos líneas (.map
devuelve un generador, por lo que necesitalist()
):Con simples
Process
es:Úselo
SimpleQueue
si todo lo que necesita esput
yget
. El primer bucle inicia todos los procesos, antes de que el segundo realice lasqueue.get
llamadas de bloqueo . No creo que haya ninguna razón para llamarp.join()
también.fuente
Una solución simple:
Salida:
fuente
Si está utilizando Python 3, puede usarlo
concurrent.futures.ProcessPoolExecutor
como una abstracción conveniente:Salida:
fuente
Modifiqué un poco la respuesta de vartec ya que necesitaba obtener los códigos de error de la función. (Gracias vertec !!! es un truco increíble)
Esto también se puede hacer con un
manager.list
pero creo que es mejor tenerlo en un dict y almacenar una lista dentro de él. De esa forma, mantenemos la función y los resultados, ya que no podemos estar seguros del orden en que se completará la lista.fuente