2009-08-06 8 views
6

je vois quand j'appuyez sur Ctrl-C pour quitter mon applicationerreur de sortie Python multitraitement

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 

J'utilise tordu au-dessus de mes propres trucs,

Je me suis inscrit le signal Ctrl-C avec le code suivant

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

et quand ils signalent d'autres à l'arrêt, il essaie de leur dire d'arrêter bien par

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

où tous mes processus sont sous une certaine forme,

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

Toute idée de ce que cette erreur? Je l'obtiens seulement quand j'ai plus d'une instance d'un fil particulier.

Répondre

5

Ceci est lié aux interactions entre les systèmes d'OS, les signaux et la façon dont ils sont traités dans le module multitraitement. Je ne suis pas vraiment sûr si c'est un bug ou une fonctionnalité, mais c'est dans un territoire un peu difficile car c'est là que python rencontre l'os.

Le problème est que le multitraitement bloque sur waitpid jusqu'à ce que l'enfant qu'il attend soit terminé. Cependant, puisque vous avez installé un gestionnaire de signal pour SIGINT et que votre programme reçoit ce signal, il interrompt l'appel système pour exécuter votre gestionnaire de signal, et waitpid se termine indiquant qu'il a été interrompu par un signal. La façon dont python gère ce cas est par exceptions.

Pour contourner ce problème, vous pouvez joindre la section incriminée (s) dans un certain temps en boucle et essayer/blocs catch comme celui-ci, que ce soit autour d'où vous attendez fils pour terminer, ou sous-classe 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 

pour déblayage à propos de multiprocessing.forking.Popen vous auriez à faire quelque chose comme ceci:

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 c'était vraiment génial. Toute bonne ressource en ligne qui expliquera quelque chose à une telle profondeur? –

0

je voyais, mais il a disparu quand je l'emportaient sur les gestionnaires de signaux avec mon propre. Utilisez reactor.run (installSignalHandlers = False) et définissez vos propres fonctions pour SIGINT, SIGTERM, etc.

Questions connexes