我有一个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()
答案 0 :(得分:10)
当进程退出时,它会尝试终止所有守护进程子进程。
这里的关键词是“尝试”。另外,“退出”。
根据您的平台和实现,可能是终止守护进程子进程的唯一方法是明确地这样做。如果父进程正常退出,它有机会明确地这样做,所以一切都很好。但如果父进程突然终止,则不会。
特别是对于CPython,如果查看the source,则终止守护进程的方式与加入非守护进程的方式相同:在atexit
函数中执行active_children()
。因此,当且仅当您的atexit
处理程序运行时,您的守护程序才会被杀死。并且,正如该模块的文档所说:
注意:当程序被Python未处理的信号杀死,检测到Python致命内部错误或调用
os._exit()
时,不会调用通过此模块注册的函数。
根据您如何杀死父级,您可以通过添加信号处理程序来拦截突然终止,从而解决此问题。但是你可能不会 - 例如,在POSIX上,SIGKILL
不能拦截,所以如果你kill -9 $PARENTPID
,这不是一个选项。
另一种选择是杀死进程组,而不仅仅是父进程。例如,如果你的父母有PID 12345,那么linux上的kill -- -12345
会杀死它及其所有孩子(假设你没有做任何花哨的事情)。