12

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

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

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

当我通过 kill 命令终止父进程时,守护进程保持活动状态并正在运行(这会在下次运行时阻塞端口)。子进程正在启动一个 SimpleHttpServer 并调用serve_forever而不做任何其他事情。我的猜测是文档的“尝试”部分意味着阻塞服务器进程正在停止进程死亡,并且它让进程成为孤立的结果。我可以让孩子将服务推送到另一个线程,并让主线程检查父进程 ID 的更改,但这似乎需要大量代码来复制守护程序功能。

有人了解为什么守护程序标志没有按描述工作吗?这在 windows8 64 位和 ubuntu12 32 位 vm 上是可重复的。

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

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

1 回答 1

11

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

这里的关键词是“尝试”。还有,“退出”。

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

特别是对于 CPython,如果您查看源代码,终止守护进程的处理方式与加入非守护进程的方式相同:通过active_children()进入atexit函数。因此,当且仅当您的atexit处理程序开始运行时,您的守护程序才会被杀死。而且,正如该模块的文档所说:

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

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

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

于 2013-04-08T20:21:32.203 回答