2009-08-31 7 views
5

sto ottenendo il seguente errore quando si utilizza il modulo di multiprocessing all'interno di un processo python daemon (usando python-daemon):Errore durante l'utilizzo del modulo multiprocessing in un demone pitone

 
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 

Il processo demone (genitore) genera un numero di processi (bambini) e quindi periodicamente esegue il polling dei processi per vedere se sono stati completati. Se il genitore rileva che uno dei processi è stato completato, tenta quindi di riavviare quel processo. È a questo punto che viene sollevata l'eccezione di cui sopra. Sembra che una volta completato uno dei processi, qualsiasi operazione che coinvolge il modulo multiprocessing genererà questa eccezione. Se eseguo il codice identico in uno script Python non daemon, viene eseguito senza errori di sorta.

EDIT:

Script di esempio

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() 

risposta

4

Ignorando SIGCLD provoca anche problemi con la subprocess modulo, a causa di un bug in quel modulo (issue 1731717, ancora aperto dal 2011-09-21).

Questo comportamento viene risolto in version 1.4.8 della libreria python-daemon; ora omette il trucco di default con SIGCLD, quindi non ha più questa sgradevole interazione con altri moduli di libreria standard.

0

Credo che ci fosse una correzione messo in tronco e 2.6 maint un po 'di tempo fa, che dovrebbe aiutare con questo si può provare a eseguire lo script in python -trunk o l'ultimo svn 2.6-maint? Sto riuscendo a tirare sulle informazioni bug

+0

L'esecuzione dello script con trunk python 2.7 produce lo stesso risultato. Ho aggiunto lo script di test che sto utilizzando al post originale. Sto facendo qualcosa di sfacciato? –

+0

Non sono sicuro, dovrei caricare un test che usa python-daemon per verificarlo. Niente mi salta in questo momento. – jnoller

0

Sembra che il vostro errore è in arrivo alla fine del processo - la tua idea è proprio all'inizio della vostra traceback, cito ...:

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

se atexit._run_exitfuncs è in esecuzione, questo indica chiaramente che il proprio processo sta terminando. Quindi, l'errore in sé è un problema secondario in un certo senso - solo da alcune funzioni che il modulo multiprocessing registrato per eseguire "at-exit" dal processo. Il problema davvero interessante è, perché il tuo processo principale sta uscendo? Penso che questo potrebbe essere dovuto ad alcune eccezioni non rilevate: provare a impostare l'hook di eccezione e visualizzare informazioni diagnostiche complete prima che si perdano a causa dell'ALTRA eccezione causata da qualsiasi processo di multiprocessing registrato all'uscita in esecuzione ...

+0

Ho spostato l'istruzione incriminata in un blocco try.except e ottengo il seguente traceback: Traceback (ultima chiamata ultima): File "bugtest.py", riga 32, in esecuzione se non process.is_alive (): File "/usr/local/lib/python2.6/multiprocessing/process.py", riga 132, in is_alive self._popen.poll() File "/usr/local/lib/python2.6/ multiprocessing/forking.py ", riga 106, nel sondaggio pid, sts = os.waitpid (self.pid, flag) OSErrore: [Errno 10] Nessun processo figlio –

+0

La mia ipotesi è che il modulo multiprocessing sia in qualche modo in disaccordo con il daemon doppia forchetta. Sfortunatamente, non capisco abbastanza bene questo materiale per eseguire il debug di questo. –

0

I sto correndo in questo anche usando il task manager distribuito di sedici sotto RHEL 5.3 con Python 2.6. La mia traceback sembra un po 'diversa, ma l'errore lo stesso:

 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 

abbastanza frustrante .. Io corro il codice tramite PDB ora, ma non hanno ancora individuato nulla.

0

Lo script di esempio originale ha "segnale di importazione" ma nessun uso di segnali. Tuttavia, avevo uno script che causava questo messaggio di errore ed era dovuto alla mia gestione del segnale, quindi spiegherò qui nel caso in cui ciò che sta accadendo per gli altri. All'interno di un gestore di segnali, stavo facendo cose con i processi (ad esempio creando un nuovo processo). Apparentemente questo non funziona, quindi ho smesso di farlo all'interno del gestore e ho corretto l'errore. (Nota: le funzioni sleep() si attivano dopo la gestione del segnale in modo che possa essere un approccio alternativo all'agire sui segnali se è necessario fare cose con i processi)

5

Il tuo problema è un conflitto tra i moduli daemon e multiprocessing, in particolare nella gestione del segnale SIGCLD (processo figlio terminato). daemon imposta SIGCLD su SIG_IGN all'avvio, che, almeno su Linux, fa sì che i bambini terminati vengano immediatamente raccolti (anziché diventare uno zombi finché il genitore non richiama wait()). Ma il test is_alive di multiprocessing invoca wait() per vedere se il processo è vivo, che fallisce se il processo è già stato raccolto.

soluzione

più semplice è solo per impostare SIGCLD tornare a SIG_DFL (comportamento predefinito - ignorare il segnale e lasciare che l'attesa parent() per il processo figlio terminato):

def run(): 
    # ... 

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

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

    while True: 
     # ... 
+1

punto bonus per usare le parole 'terminato', 'raccolto', 'zombie', e 'raccolto' nuovamente. –

Problemi correlati