Aprender sobre el multiprocesamiento de Python (de un artículo de PMOTW ) y me encantaría una aclaración sobre qué join()
está haciendo exactamente el método.
En un viejo tutorial de 2008 , establece que sin la p.join()
llamada en el código siguiente, "el proceso hijo permanecerá inactivo y no terminará, convirtiéndose en un zombi que debe matar manualmente".
from multiprocessing import Process
def say_hello(name='world'):
print "Hello, %s" % name
p = Process(target=say_hello)
p.start()
p.join()
Agregué una copia impresa del PID
y una time.sleep
para probar y, por lo que puedo decir, el proceso termina por sí solo:
from multiprocessing import Process
import sys
import time
def say_hello(name='world'):
print "Hello, %s" % name
print 'Starting:', p.name, p.pid
sys.stdout.flush()
print 'Exiting :', p.name, p.pid
sys.stdout.flush()
time.sleep(20)
p = Process(target=say_hello)
p.start()
# no p.join()
en 20 segundos:
936 ttys000 0:00.05 /Library/Frameworks/Python.framework/Versions/2.7/Reso
938 ttys000 0:00.00 /Library/Frameworks/Python.framework/Versions/2.7/Reso
947 ttys001 0:00.13 -bash
después de 20 segundos:
947 ttys001 0:00.13 -bash
El comportamiento es el mismo con p.join()
agregado al final del archivo. Python Module of the Week ofrece una explicación muy legible del módulo. ; "Para esperar hasta que un proceso haya completado su trabajo y salido, use el método join ()", pero parece que al menos OS X lo estaba haciendo de todos modos.
También me pregunto sobre el nombre del método. ¿El .join()
método está concatenando algo aquí? ¿Está concatenando un proceso con su final? ¿O simplemente comparte un nombre con el .join()
método nativo de Python ?
fuente
CPU, Memory resources
se separa del proceso principal y luego sejoin
vuelve a editar una vez que se completa el proceso secundario?Respuestas:
El
join()
método, cuando se usa conthreading
omultiprocessing
, no está relacionado constr.join()
; en realidad, no está concatenando nada. Más bien, solo significa "esperar a que este [hilo / proceso] se complete". El nombrejoin
se usa porque lamultiprocessing
API del módulo está destinada a ser similar a lathreading
API del módulo, y elthreading
módulo usajoin
para suThread
objeto. Usar el términojoin
para significar "esperar a que se complete un hilo" es común en muchos lenguajes de programación, por lo que Python también lo adoptó.Ahora, la razón por la que ve el retraso de 20 segundos con y sin la llamada a
join()
es porque, de forma predeterminada, cuando el proceso principal está listo para salir, llamará implícitamentejoin()
a todas lasmultiprocessing.Process
instancias en ejecución . Esto no está tan claramente establecido en losmultiprocessing
documentos como debería estar, pero se menciona en la sección Pautas de programación :Puede anular este comportamiento estableciendo la
daemon
bandera en elProcess
queTrue
antes de iniciar el proceso:Si lo hace, el proceso hijo finalizará tan pronto como se complete el proceso principal :
fuente
p.daemon=True
era para "iniciar un proceso en segundo plano que se ejecuta sin bloquear la salida del programa principal". Pero si "El proceso del demonio se termina automáticamente antes de que salga el programa principal", ¿cuál es exactamente su uso?daemonic
proceso hijo no es muy seguro, porque el proceso se terminará sin permitir la limpieza de los recursos abiertos que pueda tener ... (cont).multiprocessing
API está diseñada para imitar lathreading
API lo más fielmente posible. Losthreading.Thread
objetos daemonic se terminan tan pronto como sale del hilo principal, por lo que losmultiprocesing.Process
objetos daemonic se comportan de la misma manera.Sin el
join()
, el proceso principal puede completarse antes que el proceso hijo. No estoy seguro de en qué circunstancias eso conduce al zombieismo.El objetivo principal de
join()
es garantizar que un proceso hijo se haya completado antes de que el proceso principal haga algo que dependa del trabajo del proceso hijo.La etimología de
join()
es que es lo opuesto afork
, que es el término común en los sistemas operativos de la familia Unix para crear procesos secundarios. Un solo proceso se "bifurca" en varios y luego se "une" nuevamente en uno.fuente
join()
porquejoin()
es lo que se utiliza para esperarthreading.Thread
a que se complete un objeto, y lamultiprocessing
API está destinada a imitar lathreading
API tanto como sea posible.join()
es necesario en el caso de que el hilo principal necesite los resultados del trabajo de los subprocesos. Por ejemplo, si está renderizando algo y asigna 1/4 de la imagen final a cada uno de los 4 subprocesos, y desea mostrar la imagen completa cuando esté lista.No voy a explicar en detalle qué
join
es lo que hace, pero aquí está la etimología y la intuición detrás de él, que debería ayudarlo a recordar su significado más fácilmente.La idea es que la ejecución se " bifurca " en múltiples procesos de los cuales uno es el maestro, el resto trabajadores (o "esclavos"). Cuando los trabajadores terminan, se "unen" al maestro para que se pueda reanudar la ejecución en serie.
El
join
método hace que el proceso maestro espere a que un trabajador se una a él. El método podría haber sido mejor llamado "esperar", ya que ese es el comportamiento real que causa en el maestro (y así es como se llama en POSIX, aunque los hilos de POSIX también lo llaman "unirse"). La unión solo ocurre como un efecto de la cooperación adecuada de los hilos, no es algo que haga el maestro .Los nombres "fork" y "join" se han utilizado con este significado en multiprocesamiento desde 1963 .
fuente
join
puede haber precedido a su uso para referirse a la concatenación, a diferencia de lo contrario.join()
se utiliza para esperar a que finalicen los procesos de trabajo. Hay que llamarclose()
oterminate()
antes de usarjoin()
.Como mencionó @Russell, join es como lo opuesto a fork (que genera subprocesos).
Para que la unión se ejecute, debe ejecutar,
close()
lo que evitará que se envíen más tareas al grupo y saldrá una vez que se completen todas las tareas. Alternativamente, la ejecuciónterminate()
simplemente terminará deteniendo todos los procesos de trabajo inmediatamente."the child process will sit idle and not terminate, becoming a zombie you must manually kill"
esto es posible cuando el proceso principal (padre) sale pero el proceso hijo todavía se está ejecutando y, una vez completado, no tiene ningún proceso padre al que devolver su estado de salida.fuente
los
join()
llamada asegura que las líneas subsiguientes de su código no sean llamadas antes de que se completen todos los procesos de multiprocesamiento.Por ejemplo, sin el
join()
, el siguiente código llamarárestart_program()
incluso antes de que finalicen los procesos, que es similar al asincrónico y no es lo que queremos (puedes probar):fuente
Para esperar hasta que un proceso haya completado su trabajo y haya salido, use el método join ().
y
Nota Es importante unir () el proceso después de terminarlo para darle tiempo a la maquinaria de fondo para actualizar el estado del objeto para reflejar la terminación.
Este es un buen ejemplo que me ayudó a entenderlo: aquí
Una cosa que noté personalmente fue que mi proceso principal se detuvo hasta que el niño terminó su proceso usando el método join () que derrotó el punto de que yo lo usaba
multiprocessing.Process()
en primer lugar.fuente