我想创建一个父进程,这将创建许多子进程。由于父进程负责创建子进程,因此父进程不会关心子进程的状态。
由于 subprocess.call 是阻塞的,所以它不起作用。因此我使用 subprocess.Popen 来代替调用。然而,一旦子进程终止(Link),Popen 将生成僵尸(失效)进程。
有没有办法解决这个问题?
提前致谢
最佳答案
有很多方法可以解决这个问题。关键点是存在僵尸/“失效”进程,以便父进程可以收集它们的状态。
作为流程的创建者,您可以宣布忽略状态的意图。 POSIX 方法是设置标志
SA_NOCLDWAIT
(使用sigaction
)。这在 Python 中做起来有点痛苦;但是大多数类 Unix 系统允许您简单地忽略SIGCHLD
/SIGCLD
(拼写因类 Unix 系统而异),这在 Python 中很容易做到:导入信号
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
或者,如果由于某种原因这不可用或在您的系统上不起作用,您可以使用一个古老的备用技巧:不要只 fork 一次,fork 两次。在第一个 child 中,叉出第二个 child ;在第二个 child 中,使用
execve
(或类似的)来运行所需的程序;然后在第一个 child 中,退出(使用_exit
)。在原始父级中,使用wait
或waidpid
或操作系统提供的任何内容,并收集第一个子级的状态。这样做的原因是第二个 child 现在变成了“孤儿”(它的 parent ,第一个 child ,已经死了,被你原来的过程收集了)。作为孤儿,它被移交给代理父级(具体来说,“init”),代理父级始终
等待
-ing,因此立即收集所有僵尸。除了双叉,您还可以让您的子进程在它们自己的单独 session 中运行和/或放弃控制终端访问(“守护进程”,用 Unix-y 术语)。 (这有点困惑并且依赖于操作系统;我以前编写过它,但是对于一些我现在无法访问的公司代码。)
最后,您可以简单地定期收集这些进程。如果您使用的是
subprocess
模块,只要看起来方便,只需在每个进程上调用.poll
函数即可。如果进程仍在运行,这将返回None
,如果它已完成,则返回退出状态(已收集)。如果一些仍在运行,那么您的主程序可以在它们继续运行时无论如何退出;到那时,它们就变成了孤儿,就像上面的方法 #2 一样。
“忽略 SIGCHLD”方法简单易行,但缺点是会干扰创建和等待子进程的库例程。 Python 2.7 及更高版本 ( http://bugs.python.org/issue15756 ) 中有一个解决方法,但这意味着库例程看不到这些子进程中的任何故障。
[编辑:http://bugs.python.org/issue1731717用于p.wait()
,其中p
是来自subprocess.Popen
的进程; 15756 专门用于 p.poll()
;但无论如何,如果您没有修复程序,则必须求助于方法 2、3 或 4。]
关于Python:非阻塞+非失效进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16807603/