2009-06-20 72 views
4

我正在編寫一個守護程序,該守護程序會產生其他幾個子進程。在運行stop腳本後,主進程在意圖退出時繼續運行,這讓我很困惑。退出守護進程的問題

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 2009-06-23 18:55:12

+1

我按原樣試了你的代碼,減去守護進程模塊,它適用於我。你可以給你的守護進程模塊的一個鏈接?谷歌搜索揭示了一些選擇。 – grieve 2009-06-23 19:41:12

+0

對不起,我遲到的迴應,對於守護程序模塊,我使用http://pypi.python.org/pypi/python-daemon/ – btw0 2009-06-26 08:39:30

回答

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()將任何信號取消暫停,所以你可能要相應地改變你的代碼。

編輯:

下面的作品對我蠻好:

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?

1

你創建http服務器進程,但不要join()它。如果發生了什麼情況,而不是通過os.kill()來停止http服務器進程,那麼會發送一個停止處理哨點(None,就像您發送給工作人員),然後執行self.http.join()

更新:你還需要將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()-來自輸入隊列的更多東西。

此外,請注意,至少one open, hard-to-reproduce issueJoinableQueue.task_done(),這可能會咬你。