父进程不会终止多进程守护进程

时间:2013-04-08 20:08:01

标签: python multiprocessing

我有一个Python 2.7多处理进程,它不会在父进程退出时退出。我设置了守护进程标志,它应该强制它在父母死亡时退出。文档声明:

“当进程退出时,它会尝试终止所有守护进程的子进程。”

p = Process(target=_serverLaunchHelper, args=args)
p.daemon = True
print p.daemon # prints True
p.start()

当我通过kill命令终止父进程时,守护进程处于活动状态并且正在运行(在下次运行时阻塞该端口)。子进程正在启动SimpleHttpServer并调用serve_forever而不执行任何其他操作。我的猜测是文档中的“尝试”部分意味着阻塞服务器进程正在停止进程死亡,并且它会让进程因此而变为孤立状态。我可以让孩子将服务推送到另一个Thread并让主线程检查父进程id的更改,但这似乎只是复制守护进程功能的很多代码。

是否有人能够深入了解守护程序标志无法正常工作的原因?这在windows8 64位和ubuntu12 32位vm上是可重复的。

流程函数的简化版本如下:

def _serverLaunchHelper(port)
    httpd = SocketServer.TCPServer(("", port), Handler)
    httpd.serve_forever()

1 个答案:

答案 0 :(得分:10)

  

当进程退出时,它会尝试终止所有守护进程子进程。

这里的关键词是“尝试”。另外,“退出”。

根据您的平台和实现,可能是终止守护进程子进程的唯一方法是明确地这样做。如果父进程正常退出,它有机会明确地这样做,所以一切都很好。但如果父进程突然终止,则不会。

特别是对于CPython,如果查看the source,则终止守护进程的方式与加入非守护进程的方式相同:在atexit函数中执行active_children()。因此,当且仅当您的atexit处理程序运行时,您的守护程序才会被杀死。并且,正如该模块的文档所说:

  

注意:当程序被Python未处理的信号杀死,检测到Python致命内部错误或调用os._exit()时,不会调用通过此模块注册的函数。

根据您如何杀死父级,您可以通过添加信号处理程序来拦截突然终止,从而解决此问题。但是你可能不会 - 例如,在POSIX上,SIGKILL不能拦截,所以如果你kill -9 $PARENTPID,这不是一个选项。

另一种选择是杀死进程组,而不仅仅是父进程。例如,如果你的父母有PID 12345,那么linux上的kill -- -12345会杀死它及其所有孩子(假设你没有做任何花哨的事情)。