2011-06-29 50 views
3

我對這個問題提出了一個問題,並沒有得到一個足夠透徹的答案來解決這個問題(很可能是由於缺乏嚴謹的解釋我正在嘗試糾正的問題):Zombie process in python multiprocessing daemon守護進程中的Python多處理池

我想實現一個python守護進程,它使用工作池來執行命令,使用Popen。我從http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

借來的基本守護我只是改變了initdaemonize(或等同的start)和stop方法。以下是更改init方法:

def __init__(self, pidfile): 
#, stdin='/dev/null', stdout='STDOUT', stderr='STDOUT'): 
    #self.stdin = stdin 
    #self.stdout = stdout 
    #self.stderr = stderr 
    self.pidfile = pidfile 
    self.pool = Pool(processes=4) 

我沒有設置標準輸入,輸出和錯誤,這樣我可以調試與打印報表的代碼。另外,我嘗試將這個池移動到幾個地方,但這是唯一不會產生異常的地方。

這裏有更改daemonize方法:

def daemonize(self): 
    ... 

    # redirect standard file descriptors 
    #sys.stdout.flush() 
    #sys.stderr.flush() 
    #si = open(self.stdin, 'r') 
    #so = open(self.stdout, 'a+') 
    #se = open(self.stderr, 'a+', 0) 
    #os.dup2(si.fileno(), sys.stdin.fileno()) 
    #os.dup2(so.fileno(), sys.stdout.fileno()) 
    #os.dup2(se.fileno(), sys.stderr.fileno()) 

    print self.pool 

    ... 

同樣的事情,我不重定向IO,這樣我可以調試。這裏的打印用於我可以檢查游泳池的位置。

而且stop方法的變化:

def stop(self): 
    ... 

    # Try killing the daemon process 
    try: 
     print self.pool 
     print "closing pool" 
     self.pool.close() 
     print "joining pool" 
     self.pool.join() 
     print "set pool to None" 
     self.pool = None 
     while 1: 
      print "kill process" 
      os.kill(pid, SIGTERM) 

    ... 

這裏的想法是,我不僅需要擊殺過程,而且清理游泳池。 self.pool = None只是一個隨機嘗試來解決沒有奏效的問題。起初,我認爲這是一個殭屍兒童問題,當我在os.kill(pid, SIGTERM)的while循環內有self.pool.close()self.pool.join()時,發生了這種情況。這是在我決定開始通過print self.pool查看泳池位置之前。這樣做後,我相信守護進程啓動時以及停止時,池不一樣。下面是一些輸出:

[email protected]:~/pyCode/jobQueue$ sudo ./jobQueue.py start 
<multiprocessing.pool.Pool object at 0x1c543d0> 
[email protected]:~/pyCode/jobQueue$ sudo ./jobQueue.py stop 
<multiprocessing.pool.Pool object at 0x1fb7450> 
closing pool 
joining pool 
set pool to None 
kill process 
kill process 
... [ stuck in infinite loop] 

對象的不同位置推薦給我,他們是不一樣的游泳池,其中一個可能是殭屍?

CTRL+C後,這裏是我從ps aux|grep jobQueue得到:

root  21161 0.0 0.0 50384 5220 ?  Ss 22:59 0:00 /usr/bin/python ./jobQueue.py start 
root  21162 0.0 0.0  0  0 ?  Z 22:59 0:00 [jobQueue.py] <defunct> 
me  21320 0.0 0.0 7624 940 pts/0 S+ 23:00 0:00 grep --color=auto jobQueue 

我試圖移動self.pool = Pool(processes=4)到一些不同的地方。如果它被移動到start()' or daemonize()methods, print self.pool`將會拋出一個異常,說它是NoneType。另外,該位置似乎改變了會彈出的殭屍進程數量。

目前,我還沒有添加通過工作人員運行任何東西的功能。我的問題似乎與正確設置工作人員池完全相關。我希望能夠解決這個問題的任何信息或者關於創建使用工作人員池來執行一系列使用Popen的一系列命令的守護程序服務的建議。由於我沒有那麼遠,我不知道我面臨的挑戰是什麼。我想我可能只需要編寫自己的游泳池,但如果有一個很好的竅門可以讓游泳池在這裏工作,那將是驚人的。

+0

我想我已經想出了我需要做的事情,但我不知道該怎麼做。守護進程內部寫入一個pid文件。無論何時調用start或stop,它都會從文件中獲取守護進程的PID。我需要對池進程的PID做同樣的事情,但是怎麼做? –

回答

1

解決的辦法是將self.pool = Pool(process=4)作爲daemonize方法的最後一行。否則,游泳池最終會在某處丟失(可能在fork s)。然後池可以在run方法內訪問,該方法由您希望守護進程的應用程序重載。但是,在停止方法中無法訪問池,並且這樣做會導致出現NoneType異常。我相信有一個更優雅的解決方案,但這是有效的,這是我現在所擁有的。如果我希望stop在池仍在運行時發生故障,我將不得不爲run添加附加功能和某種形式的消息,但我目前不關心這一點。

+0

呃。實際上它非常簡單,我只需要將'self.pool = Pool(process = 4)'放在守護進程的'run'方法中,但這仍然不允許我使用'close'' join '很好地清理池的方法。任何其他解決方案將不勝感激。 –