thread parallel lock async python daemon multiprocessing children zombie-process

parallel - python multiprocessing windows



Python-daemon no mata a sus niƱos (3)

Cuando uso python-daemon , estoy creando subprocesos como:

import multiprocessing class Worker(multiprocessing.Process): def __init__(self, queue): self.queue = queue # we wait for things from this in Worker.run() ... q = multiprocessing.Queue() with daemon.DaemonContext(): for i in xrange(3): Worker(q) while True: # let the Workers do their thing q.put(_something_we_wait_for())

Cuando mato el proceso demoníaco de los padres (es decir, no un trabajador) con un Ctrl-C o SIGTERM, etc., los niños no mueren. ¿Cómo se mata a los niños?

Mi primer pensamiento es usar atexit para matar a todos los trabajadores, como:

with daemon.DaemonContext(): workers = list() for i in xrange(3): workers.append(Worker(q)) @atexit.register def kill_the_children(): for w in workers: w.terminate() while True: # let the Workers do their thing q.put(_something_we_wait_for())

Sin embargo, los hijos de los demonios son difíciles de manejar, y me gustaría que me diera cuenta de cómo hacer esto.

Gracias.


Atexit no hará el truco, solo se ejecuta en una terminación exitosa sin señal, vea la nota cerca de la parte superior de los docs . Debe configurar el manejo de la señal a través de uno de dos medios.

La opción de sonido más fácil: establezca el indicador del demonio en sus procesos de trabajo, según http://docs.python.org/library/multiprocessing.html#process-and-exceptions

Opción un poco más dura: el PEP-3143 parece implicar que hay una forma integrada de enganchar las necesidades de limpieza del programa en el daemon de Python.


Sus opciones son un poco limitadas. Si hacer self.daemon = True en el constructor para la clase Worker no resuelve su problema y tratar de detectar señales en el Parent (es decir, SIGTERM, SIGINT ) no funciona, es posible que tenga que probar la solución opuesta, en lugar de Si los padres matan a los niños, puede hacer que los niños se suiciden cuando el padre muere.

El primer paso es darle al constructor de PID el PID del proceso principal (puede hacerlo con os.getpid() ). Luego, en lugar de simplemente hacer self.queue.get() en el bucle de trabajo, haga algo como esto:

waiting = True while waiting: # see if Parent is at home if os.getppid() != self.parentPID: # woe is me! My Parent has died! sys.exit() # or whatever you want to do to quit the Worker process try: # I picked the timeout randomly; use what works data = self.queue.get(block=False, timeout=0.1) waiting = False except queue.Queue.Empty: continue # try again # now do stuff with data

La solución anterior verifica si el PID principal es diferente de lo que era originalmente (es decir, si el proceso secundario fue adoptado por init o lauchd porque el padre murió): consulte la reference . Sin embargo, si eso no funciona por alguna razón, puede reemplazarlo con la siguiente función (adaptada de here ):

def parentIsAlive(self): try: # try to call Parent os.kill(self.parentPID, 0) except OSError: # *beeep* oh no! The phone''s disconnected! return False else: # *ring* Hi mom! return True

Ahora, cuando el Padre muere (por cualquier razón), los Trabajadores infantiles caerán espontáneamente como moscas, ¡tal como usted quería, demonio! :-D


no puede simplemente almacenar el pid padre cuando se crea el niño por primera vez (digamos en self.myppid ) y cuando self.myppid es diferente de getppid() significa que el padre murió.

También podría usar señales para evitar la necesidad de seguir verificando si el padre ha cambiado. No conozco los detalles específicos de python, pero algo como lo que se describe aquí (en la parte inferior de la página) podría funcionar.