2009-06-20 4 views
4

Я пишу программу-демон, которая порождает несколько других дочерних процессов. После запуска сценария stop основной процесс продолжает работать, когда он предназначен для выхода, это меня действительно смутило.Проблема с выходом из процесса daemonized

import daemon, signal 
from multiprocessing import Process, cpu_count, JoinableQueue 
from http import httpserv 
from worker import work 

class Manager: 
    """ 
    This manager starts the http server processes and worker 
    processes, creates the input/output queues that keep the processes 
    work together nicely. 
    """ 
    def __init__(self): 
     self.NUMBER_OF_PROCESSES = cpu_count() 

    def start(self): 
     self.i_queue = JoinableQueue() 
     self.o_queue = JoinableQueue() 

     # Create worker processes 
     self.workers = [Process(target=work, 
           args=(self.i_queue, self.o_queue)) 
         for i in range(self.NUMBER_OF_PROCESSES)] 
     for w in self.workers: 
      w.daemon = True 
      w.start() 

     # Create the http server process 
     self.http = Process(target=httpserv, args=(self.i_queue, self.o_queue)) 
     self.http.daemon = True 
     self.http.start() 

     # Keep the current process from returning 
     self.running = True 
     while self.running: 
      time.sleep(1) 

    def stop(self): 
     print "quiting ..." 

     # Stop accepting new requests from users 
     os.kill(self.http.pid, signal.SIGINT) 

     # Waiting for all requests in output queue to be delivered 
     self.o_queue.join() 

     # Put sentinel None to input queue to signal worker processes 
     # to terminate 
     self.i_queue.put(None) 
     for w in self.workers: 
      w.join() 
     self.i_queue.join() 

     # Let main process return 
     self.running = False 


import daemon 

manager = Manager() 
context = daemon.DaemonContext() 
context.signal_map = { 
     signal.SIGHUP: lambda signum, frame: manager.stop(), 
     } 

context.open() 
manager.start() 

stop сценарий просто один лайнер os.kill(pid, signal.SIGHUP), но после того, что дети процессы (рабочие процессы и процесс сервера HTTP) заканчивается хорошо, но основной процесс просто остается там, я не знаю, что держит это от возвращения.

+0

Вы видите, что «уходит ...» распечатывается? – grieve

+1

Я пробовал свой код как есть, минус модуль демонов, и он работает для меня. Можете ли вы дать ссылку на вашу версию модуля демонов? Поиск в Google показывает несколько вариантов. – grieve

+0

Извините за мой поздний ответ, для модуля daemon я использую http://pypi.python.org/pypi/python-daemon/ – btw0

ответ

1

Я попробовал другой подход, и это кажется сработавшим (обратите внимание, что я извлек часть кода демона, поскольку у меня не было установлен этот модуль).

import signal 

class Manager: 
    """ 
    This manager starts the http server processes and worker 
    processes, creates the input/output queues that keep the processes 
    work together nicely. 
    """ 
    def __init__(self): 
     self.NUMBER_OF_PROCESSES = cpu_count() 

    def start(self): 

     # all your code minus the loop 

     print "waiting to die" 

     signal.pause() 

    def stop(self): 
     print "quitting ..." 

     # all your code minus self.running 


manager = Manager() 

signal.signal(signal.SIGHUP, lambda signum, frame: manager.stop()) 

manager.start() 

Одно предупреждение, что signal.pause() будет возобновите для любого сигнала, так что вы можете изменить свой код соответственно.

EDIT:

Следующие прекрасно работает для меня:

import daemon 
import signal 
import time 

class Manager: 
    """ 
    This manager starts the http server processes and worker 
    processes, creates the input/output queues that keep the processes 
    work together nicely. 
    """ 
    def __init__(self): 
     self.NUMBER_OF_PROCESSES = 5 

    def start(self): 

     # all your code minus the loop 

     print "waiting to die" 
     self.running = 1 
     while self.running: 
      time.sleep(1) 

     print "quit" 



    def stop(self): 
     print "quitting ..." 

     # all your code minus self.running 

     self.running = 0 


manager = Manager() 

context = daemon.DaemonContext() 
context.signal_map = {signal.SIGHUP : lambda signum, frame: manager.stop()} 

context.open() 
manager.start() 

Какую версию Python вы используете?

+0

Я сам не обрабатываю обработку сигнала, это связано с модулем демона от http://pypi.python.org/pypi/python-daemon/ – btw0

1

Вы создаете процесс http-сервера, но не join(). Что произойдет, если вместо того, чтобы делать os.kill(), чтобы остановить процесс HTTP-сервера, вы отправляете ему контрольный стоп-сигнал (None, как и вы отправляете рабочим), а затем выполните self.http.join()?

Update: Кроме того, необходимо отправить None часовые в очередь один раз ввода для каждого работника. Вы можете попробовать:

for w in self.workers: 
     self.i_queue.put(None) 
    for w in self.workers: 
     w.join() 

N.B. Причина, по которой вам нужны две петли, заключается в том, что если вы поместите None в очередь в том же цикле, который делает join(), то None может быть поднят работником, отличным от w, поэтому присоединение к w приведет к блокировке вызывающего.

Вы не показываете код для рабочих или http-сервера, поэтому я предполагаю, что они хорошо себя ведут с точки зрения вызова task_done и т. Д., И каждый работник уйдет, как только он увидит None, без get() -ing больше вещей из входной очереди.

Также обратите внимание, что существует не менее one open, hard-to-reproduce issue с JoinableQueue.task_done(), что может быть вам кусать.

+0

В то время как истинный цикл в моем коде был действительно self.http.join(), но один процесс не завершился, затем я заменил его на цикл while, но процесс все еще не уходит :( – btw0

+0

См. мое обновление. Измененная версия вашего скрипта с моими изменениями завершается корректно, по крайней мере, в моей среде , –

 Смежные вопросы

  • Нет связанных вопросов^_^