Python守护进程不会杀死它的孩子

2024-05-16 00:33:40 发布

您现在位置:Python中文网/ 问答频道 /正文

使用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等杀死父守护进程(即不是工作进程)时,子进程不会死亡。怎么杀孩子?

我的第一个想法是用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())

然而,守护进程的子进程是很难处理的事情,我不得不思考和输入应该如何做。

谢谢你。


Tags: theinselfforqueue进程defwith
3条回答

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

听起来更简单的选项:在工作进程上设置守护进程标志,每http://docs.python.org/library/multiprocessing.html#process-and-exceptions

听起来有些困难的选项:PEP-3143似乎意味着python守护进程中有一种内置的方法来钩住程序清理需求。

你的选择有点有限。如果在Worker类的构造函数中执行self.daemon = True操作无法解决问题,并且尝试捕获父类中的信号(即SIGTERM, SIGINT)也无法工作,则可能必须尝试相反的解决方案-而不是让父类杀死子类,而是让子类在父类死亡时自杀。

第一步是将构造函数赋给父进程的WorkerPID(可以使用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

当第一次创建子进程时(比如在self.myppid)和self.myppidgetppid()不同时,不能只存储父进程的pid,这意味着父进程已经死亡。

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

相关问题 更多 >