Pregunta

Cuando usas Python-Demon, Estoy creando subprocesos me gusta:

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 principal (es decir, no un trabajador) con un CTRL-C o Sigterm, etc., los niños no mueren. ¿Cómo uno mata a los niños?

Mi primer pensamiento es usar atexit Para matar a todos los trabajadores, me gusta:

 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 cosas difíciles de manejar, y estaría obligado por pensamientos y aportes sobre cómo se debe hacer esto.

Gracias.

¿Fue útil?

Solución

Tus opciones son un poco limitadas. Si hace self.daemon = True en el constructor para el Worker La clase no resuelve su problema e intenta atrapar señales en el padre (es decir, SIGTERM, SIGINT) no funciona, es posible que deba probar la solución opuesta: en lugar de que los padres maten a los niños, puede que los niños se suiciden cuando los padres mueran.

El primer paso es dar al constructor a Worker la PID del proceso principal (puede hacer esto con os.getpid()). Entonces, en lugar de simplemente hacer self.queue.get() En el bucle de trabajadores, haz 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 originalmente era (es decir, si el proceso del niño fue adoptado por init o lauchd Porque el padre murió) - ver referencia. Sin embargo, si eso no funciona por alguna razón, puede reemplazarlo con la siguiente función (adaptada de aquí):

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 de los niños caerán espontáneamente como moscas, tal como quisieras, ¡Daemon! :-D

Otros consejos

¿No puedes simplemente almacenar el PID de los padres cuando se crea el niño por primera vez? self.myppid) y cuando self.myppid es diferente de getppid() significa que el padre murió.

También puede usar señales para evitar la necesidad de seguir revisando si el padre ha cambiado. No conozco los detalles de Python, sino algo así como lo que se describe aquí (en la parte inferior de la página) Podría funcionar.

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

La opción de sonido más fácil: configure la bandera de demonio en los procesos de su trabajador, según http://docs.python.org/library/multiprocessing.html#process-and-excepciones

Opción algo más difícil: PEP-3143 Parece implicar que hay una forma incorporada de enganchar las necesidades de limpieza del programa en Python-Demon.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top