Python:非阻塞+非失效进程

标签 python subprocess

我想创建一个父进程,这将创建许多子进程。由于父进程负责创建子进程,因此父进程不会关心子进程的状态。

由于 subprocess.call 是阻塞的,所以它不起作用。因此我使用 subprocess.Popen 来代替调用。然而,一旦子进程终止(Link),Popen 将生成僵尸(失效)进程。

有没有办法解决这个问题?

提前致谢

最佳答案

有很多方法可以解决这个问题。关键点是存在僵尸/“失效”进程,以便父进程可以收集它们的状态。

  1. 作为流程的创建者,您可以宣布忽略状态的意图。 POSIX 方法是设置标志SA_NOCLDWAIT(使用sigaction)。这在 Python 中做起来有点痛苦;但是大多数类 Unix 系统允许您简单地忽略 SIGCHLD/SIGCLD(拼写因类 Unix 系统而异),这在 Python 中很容易做到:

    导入信号

    signal.signal(signal.SIGCHLD, signal.SIG_IGN)

  2. 或者,如果由于某种原因这不可用或在您的系统上不起作用,您可以使用一个古老的备用技巧:不要只 fork 一次,fo​​rk 两次。在第一个 child 中,叉出第二个 child ;在第二个 child 中,使用 execve (或类似的)来运行所需的程序;然后在第一个 child 中,退出(使用 _exit)。在原始父级中,使用 waitwaidpid 或操作系统提供的任何内容,并收集第一个子级的状态。

    这样做的原因是第二个 child 现在变成了“孤儿”(它的 parent ,第一个 child ,已经死了,被你原来的过程收集了)。作为孤儿,它被移交给代理父级(具体来说,“init”),代理父级始终等待-ing,因此立即收集所有僵尸。

  3. 除了双叉,您还可以让您的子进程在它们自己的单独 session 中运行和/或放弃控制终端访问(“守护进程”,用 Unix-y 术语)。 (这有点困惑并且依赖于操作系统;我以前编写过它,但是对于一些我现在无法访问的公司代码。)

  4. 最后,您可以简单地定期收集这些进程。如果您使用的是 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/

相关文章:

Python 从线程更新 Matplotlib

python - gpg --passphrase-fd 不适用于 python 3 子进程

java - 使用密码执行 Java 进程

python - subprocess.Popen 在 WSL Linux 上花费太长时间

python - 使用 subprocess.Popen 重复命令

python - 杀死Python脚本中没有响应的exe文件

python - 不能对 flask 使用 PUT 方法

Python 相当于 curls --form : Create multipart form-data post request with data in "form" parameter

Python 列表到 Pandas 数据框的字典

python字符串unicode问题