2009-08-31 9 views
5

Estoy recibiendo el siguiente error cuando se utiliza el módulo de multiprocesamiento dentro de un proceso de demonio de pitón (Python usando -daemon):error durante el uso de módulo de multiprocesamiento en un demonio de pitón

 
Traceback (most recent call last): 
    File "/usr/local/lib/python2.6/atexit.py", line 24, in _run_exitfuncs 
    func(*targs, **kargs) 
    File "/usr/local/lib/python2.6/multiprocessing/util.py", line 262, in _exit_function 
    for p in active_children(): 
    File "/usr/local/lib/python2.6/multiprocessing/process.py", line 43, in active_children 
    _cleanup() 
    File "/usr/local/lib/python2.6/multiprocessing/process.py", line 53, in _cleanup 
    if p._popen.poll() is not None: 
    File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 106, in poll 
    pid, sts = os.waitpid(self.pid, flag) 
OSError: [Errno 10] No child processes 

El proceso de demonio (padre) engendra una serie de procesos (hijos) y luego sondea periódicamente los procesos para ver si se han completado. Si el padre detecta que uno de los procesos se ha completado, intenta reiniciar ese proceso. Es en este punto que se plantea la excepción anterior. Parece que una vez que se completa uno de los procesos, cualquier operación que involucre el módulo de multiprocesamiento generará esta excepción. Si ejecuto el código idéntico en un script python no daemon, se ejecuta sin errores de ningún tipo.

EDIT:

Script de ejemplo

from daemon import runner 

class DaemonApp(object): 
    def __init__(self, pidfile_path, run): 
     self.pidfile_path = pidfile_path 
     self.run = run 

     self.stdin_path = '/dev/null' 
     self.stdout_path = '/dev/tty' 
     self.stderr_path = '/dev/tty' 

def run(): 
    import multiprocessing as processing 
    import time 
    import os 
    import sys 
    import signal 

    def func(): 
     print 'pid: ', os.getpid() 
     for i in range(5): 
      print i 
      time.sleep(1) 

    process = processing.Process(target=func) 
    process.start() 

    while True: 
     print 'checking process' 
     if not process.is_alive(): 
      print 'process dead' 
      process = processing.Process(target=func) 
      process.start() 
     time.sleep(1) 

# uncomment to run as daemon 
app = DaemonApp('/root/bugtest.pid', run) 
daemon_runner = runner.DaemonRunner(app) 
daemon_runner.do_action() 

#uncomment to run as regular script 
#run() 

Respuesta

4

Ignorando SIGCLD también causa problemas con el subprocess módulo, debido a un error en ese módulo (issue 1731717, aún abierto desde 2011-09-21).

Este comportamiento se trata en version 1.4.8 de la biblioteca python-daemon; ahora omite el truco predeterminado con SIGCLD, por lo que ya no tiene esta interacción desagradable con otros módulos de biblioteca estándar.

0

Creo que hubo un arreglo poner en tronco y 2,6 maint hace un rato que debería ayudar con esto se puede tratar de ejecutar el script en Python -trunk o el último 2.6-maint svn? Estoy fallando para levantar la información de errores

+0

Ejecutar el script con el tronco de python 2.7 produce el mismo resultado. Agregué el script de prueba que estoy usando a la publicación original. ¿Estoy haciendo algo descaradamente mal? –

+0

No estoy seguro, tendría que cargar una prueba que use python-daemon para verificarlo. Nada salta a mí en este momento. – jnoller

0

Parece que el error está llegando al final de su proceso - que su idea es en el comienzo mismo de su rastreo, y cito ...:

File "/usr/local/lib/python2.6/atexit.py", line 24, in _run_exitfuncs 
    func(*targs, **kargs) 

si atexit._run_exitfuncs se está ejecutando, esto muestra claramente que su propio proceso está finalizando. Por lo tanto, el error en sí mismo es un problema menor en cierto sentido, solo por alguna función que el módulo multiprocessing haya registrado para ejecutar "at-exit" desde su proceso. El problema realmente interesante es: ¿POR QUÉ está saliendo su proceso principal? Creo que esto puede deberse a alguna excepción no detectada: intente configurar el enganche de excepción y muestre información de diagnóstico abundante antes de que se pierda por la OTRA excepción causada por lo que sea que ese multiprocesamiento esté registrado para ejecutar en la salida ...

+0

Envolví la declaración ofensiva en un bloque try..except y obtengo la siguiente trazabilidad: Traceback (última llamada más reciente): Archivo "bugtest.py", línea 32, en ejecución si no process.is_alive (): Archivo "/usr/local/lib/python2.6/multiprocessing/process.py", línea 132, en is_alive self._popen.poll() Archivo "/usr/local/lib/python2.6/ multiprocesamiento/forking.py ", línea 106, en la encuesta pid, sts = os.waitpid (auto.pid, indicador) OSError: [Errno 10] Ningún proceso secundario –

+0

Supongo que el módulo de multiprocesamiento está de alguna manera en desacuerdo con el daemon doble tenedor Desafortunadamente, no entiendo este material lo suficientemente bien para depurar esto. –

0

I Estoy corriendo en esto también usando el administrador de tareas distribuidas de apio en RHEL 5.3 con Python 2.6. Mi rastreo se ve un poco diferente, pero el error de la misma:

 File "/usr/local/lib/python2.6/multiprocessing/pool.py", line 334, in terminate 
    self._terminate() 
    File "/usr/local/lib/python2.6/multiprocessing/util.py", line 174, in __call__ 
    res = self._callback(*self._args, **self._kwargs) 
    File "/usr/local/lib/python2.6/multiprocessing/pool.py", line 373, in _terminate_pool 
    p.terminate() 
    File "/usr/local/lib/python2.6/multiprocessing/process.py", line 111, in terminate 
    self._popen.terminate() 
    File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 136, in terminate 
    if self.wait(timeout=0.1) is None: 
    File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 121, in wait 
    res = self.poll() 
    File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 106, in poll 
    pid, sts = os.waitpid(self.pid, flag) 
OSError: [Errno 10] No child processes 

muy frustrante .. estoy ejecutando el código a través de AP, pero no han visto nada todavía.

0

La secuencia de comandos de muestra original tiene "señal de importación" pero no utiliza señales. Sin embargo, tuve un script que causaba este mensaje de error y se debió a mi manejo de la señal, así que explicaré aquí en caso de que sea lo que está sucediendo para los demás. Dentro de un manejador de señal, estaba haciendo cosas con los procesos (por ejemplo, creando un nuevo proceso). Aparentemente, esto no funciona, así que dejé de hacerlo dentro del controlador y solucioné el error. (Nota: las funciones sleep() se activan después del manejo de la señal, por lo que puede ser un enfoque alternativo para actuar sobre las señales si necesita hacer cosas con los procesos)

5

Su problema es un conflicto entre el daemon y los módulos de multiprocesamiento, en particular en su manejo de la señal SIGCLD (proceso hijo terminado). daemon establece SIGCLD en SIG_IGN al iniciarse, lo que, al menos en Linux, hace que los hijos finalizados sean inmediatamente cosechados (en lugar de convertirse en zombis hasta que el padre invoque wait()). Pero la prueba is_alive de multiprocesamiento invoca wait() para ver si el proceso está activo, lo que falla si el proceso ya se ha cosechado.

solución

más simple es sólo para establecer SIGCLD de nuevo a SIG_DFL (comportamiento por defecto - ignorar la señal y dejar que la espera de los padres() para el proceso hijo terminado):

def run(): 
    # ... 

    signal.signal(signal.SIGCLD, signal.SIG_DFL) 

    process = processing.Process(target=func) 
    process.start() 

    while True: 
     # ... 
+1

Punto de bonificación por usar las palabras 'terminado', 'cosechado', 'zombi' y 'cosechado' de nuevo. –

Cuestiones relacionadas