2011-10-19 4 views
2

Compte tenu de ce programme Python:Processus Python multiprocessing.Queue +: terminer correctement les deux programmes

# commented out code are alternatives I tried that don't work. 

from multiprocessing import Process, Queue 
#from multiprocessing import Process, JoinableQueue as Queue 

def start_process(queue): 
    # queue.cancel_join_thread() 
    while True: 
     print queue.get() 

if __name__ == '__main__': 
    queue = Queue() 
    # queue.cancel_join_thread() 

    process = Process(target=start_process, args=(queue,)) 
    process.start() 

    queue.put(12) 
    process.join() 

Quand je tue ce programme avec CTRL-C, cela se produit:

$> python queuetest.py 
12 
^CTraceback (most recent call last): 
    File "queuetest.py", line 19, in <module> 
    process.join() 
    File ".../python2.7/multiprocessing/process.py", line 119, in join 
    res = self._popen.wait(timeout) 
Process Process-1: 
    File ".../python2.7/multiprocessing/forking.py", line 122, in wait 
Traceback (most recent call last): 
    return self.poll(0) 
    File ".../python2.7/multiprocessing/forking.py", line 107, in poll 
    pid, sts = os.waitpid(self.pid, flag) 
    File ".../python2.7/multiprocessing/process.py", line 232, in _bootstrap 
KeyboardInterrupt 
    self.run() 
    File ".../python2.7/multiprocessing/process.py", line 88, in run 
    self._target(*self._args, **self._kwargs) 
    File "queuetest.py", line 9, in start_process 
    print queue.get() 
    File ".../python2.7/multiprocessing/queues.py", line 91, in get 
    res = self._recv() 
KeyboardInterrupt 

.. comment puis-je bien terminer les deux processess sur le signal? Ce que je veux réaliser: Dans mon programme non-minimal, le second processus contient un SocketServer et nécessite une interface de ligne de commande interactive supplémentaire.

+0

http://bugs.python.org/issue8237 semble très similaire, mais semble être sur les files d'attente pleines. Besoin d'une solution de contournement cependant. – peritus

Répondre

3

Une solution consiste à envoyer un message spécifique (par exemple, la chaîne 'exit' dans mon exemple) via la file d'attente, pour terminer le worker (processus enfant) normal. Comme le signal CTRL-C est envoyé à tous les enfants, nous devons l'ignorer. Voici un exemple de code:

from multiprocessing import Process, Queue 

def start_process(queue): 
    while True: 
    try: 
     m = queue.get() 
     if m == 'exit': 
      print 'cleaning up worker...' 
      # add here your cleaning up code 
      break 
     else: 
      print m 
    except KeyboardInterrupt: 
     print 'ignore CTRL-C from worker' 


if __name__ == '__main__': 
    queue = Queue() 

    process = Process(target=start_process, args=(queue,)) 
    process.start() 

    queue.put(12) 

    try: 
    process.join() 
    except KeyboardInterrupt: 
    print 'wait for worker to cleanup...' 
    queue.put('exit') 
    process.join() 

    ## or to kill anyway the worker if is not terminated after 5 seconds ... 
    ## process.join(5) 
    ## if process.is_alive(): 
    ##  process.terminate() 
+0

Merci! Cela fonctionne bien si le processus ne bloque que sur queue.get() (et dans mon cas il bloque également sur socket.recv()). J'ai décidé de déplacer l'interface cli vers un http basé pour plus de simplicité. Plus facile et plus fiable. – peritus

Questions connexes