Python-daemon不会杀死它的孩子

时间:2010-03-30 02:59:57

标签: python daemon multiprocessing children zombie-process

使用python-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等杀死父守护进程(即不是Worker)时,孩子们不会死。如何杀死孩子?

我的第一个想法是使用atexit杀死所有工人,喜欢:

 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())

然而,守护进程的孩子们处理起来很棘手,我不得不考虑如何做到这一点的想法和意见。

谢谢。

3 个答案:

答案 0 :(得分:31)

您的选择有点受限。如果在self.daemon = True类的构造函数中执行Worker无法解决您的问题并尝试捕获父级中的信号(即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是否与最初的PID不同(即,initlauchd采用子进程,因为父进程已经死亡) - 请参阅{ {3}}。但是,如果由于某种原因这不起作用,您可以使用以下函数替换它(改编自reference):

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 :(得分:3)

你不能只在第一次创建孩子时存储父pid(让我们说在self.myppid中),而self.myppidgetppid()不同意味着父母死了。< / p>

您还可以使用信号来避免检查父项是否已更改。我不知道python的具体细节,但是像here (at the bottom of the page)所描述的那样可能有用。

答案 2 :(得分:2)

Atexit不会这样做 - 它只能在成功的非信号终止时运行 - 请参阅docs顶部附近的注释。您需要通过两种方法之一设置信号处理。

更容易发声的选项:根据http://docs.python.org/library/multiprocessing.html#process-and-exceptions

在工作进程上设置守护程序标志

有点难听的选项:PEP-3143似乎意味着有一种内置的方法来挂钩python-daemon中的程序清理需求。

相关问题