2010-03-30 40 views
20

-daemon的不殺它的孩子

import multiprocessing 

class Worker(multiprocessing.Process): 
    def __init__(self, queue): 
     self.queue = queue # we wait for things from this in Worker.run() 

    ... 

q = multiprocessing.Queue() 

with daemon.DaemonContext(): 
    for i in xrange(3): 
     Worker(q) 

    while True: # let the Workers do their thing 
     q.put(_something_we_wait_for()) 

當我殺死惡魔的父進程(即不是工人)與按Ctrl-C或SIGTERM等等,孩子們不會死。如何殺死孩子?

我首先想到的是用atexit殺死所有的工人,likeso:

with daemon.DaemonContext(): 
    workers = list() 
    for i in xrange(3): 
     workers.append(Worker(q)) 

    @atexit.register 
    def kill_the_children(): 
     for w in workers: 
      w.terminate() 

    while True: # let the Workers do their thing 
     q.put(_something_we_wait_for()) 

然而,守護的孩子們棘手的事情要處理,而且我不得不爲的想法和投入如何這應該完成。

謝謝。

+11

殺死你的孩子確實看起來像一個「守護神」的事情...... – ewall 2010-03-30 03:29:40

+0

絕對。這個守護進程*不符合規範。 – 2010-04-07 14:58:16

+14

這不是Python嗎?你不能只從「邪惡的進口殺嬰」或什麼東西? – Syntactic 2010-04-07 15:00:32

回答

31

您的選擇有限。如果在Worker類的構造函數中執行self.daemon = True無法解決您的問題並嘗試捕獲父級(即SIGTERM, SIGINT)中的信號不起作用,那麼您可能必須嘗試相反的解決方案 - 而不是讓父項殺死子項,當父母去世時,你可以讓孩子自殺。

第一步是給構造函數Worker父進程的PID(你可以用os.getpid()來做到這一點)。然後,而不是僅僅做self.queue.get()在工人環路,做這樣的事情:

waiting = True 
while waiting: 
    # see if Parent is at home 
    if os.getppid() != self.parentPID: 
     # woe is me! My Parent has died! 
     sys.exit() # or whatever you want to do to quit the Worker process 
    try: 
     # I picked the timeout randomly; use what works 
     data = self.queue.get(block=False, timeout=0.1) 
     waiting = False 
    except queue.Queue.Empty: 
     continue # try again 
# now do stuff with data 

上述檢查的解決方案,看是否父PID是比它原本是不同的(也就是說,如果孩子進程由於父母死亡,通過initlauchd) - 見reference。但是,如果不出於某種原因,你可以用下面的函數(改編自here)替換它:

def parentIsAlive(self): 
    try: 
     # try to call Parent 
     os.kill(self.parentPID, 0) 
    except OSError: 
     # *beeep* oh no! The phone's disconnected! 
     return False 
    else: 
     # *ring* Hi mom! 
     return True 

現在,當父母去世(無論何種原因),孩子的工人將自然落下像蒼蠅一樣 - 就像你想的那樣,你守護着! :-D

+1

聰明的解決方案和很好的解釋! – 2010-04-12 02:04:47

+2

我真的想給你超過1分這個答案:D – edomaur 2010-11-11 14:52:07

+0

是不是這個忙等待,因爲queue.get不再阻塞? IMO最好在主線程中用atexit在隊列中插入一個特殊的對象(比如None),如果他們得到None對象,讓子項sys.exit()。 – Cedric 2017-12-13 21:03:44

2

Atexit不會訣竅 - 它只能在成功的非信號終止時運行 - 請參閱docs頂部附近的註釋。您需要通過以下兩種方式之一來設置信號處理。

越容易冠冕堂皇的選項:設置守護標誌在你的工作進程,每http://docs.python.org/library/multiprocessing.html#process-and-exceptions

稍硬的冠冕堂皇的選項:PEP-3143似乎暗示有鉤在python-程序清理需要一個內置的方式守護進程。

+0

謝謝阿瑟。順便提一下,我發佈的相關問題是http://stackoverflow.com/questions/2546276/python-process-wont-call-atexit - 它涵蓋了其中的一些主題。我想知道確保兒童死亡(或不成爲殭屍)的模式 - 我猜多處理守護進程標誌會有所作爲 - 是否涵蓋所有情況?什麼情況? – 2010-04-08 00:29:01

3

你不能只存儲父PID孩子在首次創建時(讓我們在self.myppid說),當self.myppidgetppid() diferent意味着父死亡。

您也可以使用信號來避免需要繼續檢查父代是否已更改。我不知道Python的具體細節,但像here (at the bottom of the page)可能的工作。

+1

嗯,這實際上*可能*工作 - 如果父母死亡(即''init'(對於Linux)或'launchd'(對於Mac OS X)採用孩子,'os.getppid()'應該返回1。 – 2010-04-09 21:37:51

相關問題