2009-08-06 23 views
6

que estoy viendo esto cuando presiono Ctrl-C para salir de mi aplicaciónmultiprocesamiento Python error de salida

Error in atexit._run_exitfuncs: 
Traceback (most recent call last): 
    File "/usr/lib/python2.6/atexit.py", line 24, in _run_exitfuncs 
    func(*targs, **kargs) 
    File "/usr/lib/python2.6/multiprocessing/util.py", line 269, in _exit_function 
    p.join() 
    File "/usr/lib/python2.6/multiprocessing/process.py", line 119, in join 
    res = self._popen.wait(timeout) 
    File "/usr/lib/python2.6/multiprocessing/forking.py", line 117, in wait 
    return self.poll(0) 
    File "/usr/lib/python2.6/multiprocessing/forking.py", line 106, in poll 
    pid, sts = os.waitpid(self.pid, flag) 
OSError: [Errno 4] Interrupted system call 
Error in sys.exitfunc: 
Traceback (most recent call last): 
    File "/usr/lib/python2.6/atexit.py", line 24, in _run_exitfuncs 
    func(*targs, **kargs) 
    File "/usr/lib/python2.6/multiprocessing/util.py", line 269, in _exit_function 
    p.join() 
    File "/usr/lib/python2.6/multiprocessing/process.py", line 119, in join 
    res = self._popen.wait(timeout) 
    File "/usr/lib/python2.6/multiprocessing/forking.py", line 117, in wait 
    return self.poll(0) 
    File "/usr/lib/python2.6/multiprocessing/forking.py", line 106, in poll 
    pid, sts = os.waitpid(self.pid, flag) 
OSError: [Errno 4] Interrupted system call 

estoy usando trenzado en la parte superior de mi propio material,

que registró la señal Ctrl-C con el siguiente código

def sigHandler(self, arg1, arg2): 
     if not self.backuped: 
      self.stopAll() 
     else: 
      out('central', 'backuped ALREADY, now FORCE exiting') 
      exit() 


    def stopAll(self): 
     self.parserM.shutdown() 
     for each in self.crawlM: 
      each.shutdown() 
     self.backup() 
     reactor.stop() 

y cuando la señal de apagado a los demás, se trata de decirle a la parada bien través

exit = multiprocessing.Event() 
def shutdown(self): 
    self.exit.set() 

donde todos mis procesos son de alguna forma,

def run(self): 
    while not self.exit.is_set(): 
     do something 
    out('crawler', 'crawler exited sucessfully') 

Cualquier idea de lo que es este error? Solo lo obtengo cuando tengo más de una instancia de un hilo en particular.

Respuesta

5

Esto está relacionado con las interacciones llamadas del sistema operativo, las señales y cómo se maneja en el módulo de multiprocesamiento. No estoy seguro si es un error o una característica, pero está en un territorio algo complicado ya que es donde Python se encuentra con el sistema operativo.

El problema es que el multiprocesamiento está bloqueando en waitpid hasta que el elemento secundario que está esperando ha finalizado. Sin embargo, dado que ha instalado un manejador de señal para SIGINT y su programa recibe esta señal, interrumpe la llamada al sistema para ejecutar su manejador de señal, y waitpid sale indicando que fue interrumpido por una señal. La forma en que python maneja este caso es por excepciones.

Como solución, puede encerrar la sección (s) infractor en un bucle while y tratar de bloques/captura de este tipo, ya sea alrededor de donde se espera a que las discusiones a fin, o subclase multiprocessing.Popen:

import errno 
from multiprocessing import Process 

p = Process(target=func, args=stuff) 
p.start() 
notintr = False 
while not notintr: 
    try: 
    p.join() # "Offending code" 
    notintr = True 
    except OSError, ose: 
    if ose.errno != errno.EINTR: 
     raise ose 

para curioseaba con multiprocessing.forking.Popen que tendría que hacer algo como esto:

import errno 
from multiprocessing import Process 
from multiprocessing.forking import Popen 
import os 

# see /path/to/python/libs/multiprocessing/forking.py 
class MyPopen(Popen): 
    def poll(self, flag=os.WNOHANG): # from forking.py 
    if self.returncode is None: # from forking.py 
     notintr = False 
     while not notintr: 
     try: 
      pid, sts = os.waitpid(self.pid, flag) # from forking.py 
      notintr = True 
     except OSError, ose: 
      if ose.errno != errno.EINTR: 
      raise ose 
     # Rest of Popen.poll from forking.py goes here 

p = Process(target=func args=stuff) 
p._Popen = p 
p.start() 
p.join() 
+0

wow eso fue realmente genial. ¿Algún buen recurso en línea que explique algo a tal profundidad? –

0

esto veía, pero se fue cuando me hizo caso omiso de los gestores de señales con la mía. Utilice reactor.run (installSignalHandlers = False) y defina sus propias funciones para SIGINT, SIGTERM, etc.

Cuestiones relacionadas