请教Python中subprocess的Popen产生僵尸进程的问题
例如这个例子:
import subprocess
b = subprocess.Popen(“ping www.baidu.com”,shell=True)
a = subprocess.Popen(“ls -al”,shell=True)
#b.wait()“一直在运行”
#a.wait()“执行马上就结束”
按照如上所示,有以下几种情况,
场景一
同时注释 a.wait(),b.wait()
并没有僵尸进程的出现
场景二
注释 a.wait()
出现执行命令 a 的僵尸进程的出现
场景三
注释 b.wait()
和场景一一样,没有出现僵尸进程
场景四
同时不注释
和场景二一样,出现执行 a 进程的僵尸进程出现
考虑到以上执行结果,以及僵死进程出现的原因和主进程相关的原因
我的想法如下:
Popen.wait()是说明主进程等待子进程结束才结束,现在普遍用这个方法来避免产生僵尸进程,
而我的情况不太一样,如果同时注释,说明 a 进程执行完,b 仍然在执行,主进程和 a 进程同时退出,不产生僵尸进程,而场景二,注释 a 的情况下,运行程序,a 进程执行完,b 进程仍然在执行,但是调用了 b.wait()的函数,导致主进程一直在等待着 b 进程的结束,但是 b 进程一直结束不了,因此主进程结束不了,导致产生 a 进程的僵尸进程,场景三的时候,同场景一原理一样,a 和主进程同时结束,这里也是相当于主进程和 a 子进程同时退出,不会产生僵尸进程,最后一个场景,也是和场景二一样。因此,归根结底,就是保证不会一直在运行的子进程和主进程同时退出,就不会导致产生僵尸进程,不知道这个解释是不是正确,请大家来帮我看看。
请教Python中subprocess的Popen产生僵尸进程的问题
我来一一说明你的问题
1. Popen.wait()只是告诉主进程要等待子进程,真正的意义是主进程要去清理子进程结束后剩余的信息,主进程不一定会接着退出。
2. 僵尸进程是由于主进程没有调用 wait 而导致的。那么主进程没有调用 wait 是不是一定会出现僵尸进程呢?答案是不一定,因为主进程早于子进程退出,那么子进程就成了孤儿进程,孤儿进程会被 init 进程(pid 1)托管然后 init 进程会对这些孤儿进程进行 wait。
2.1 回到你的问题,若有调用 wait,那么这个子进程必然不会成为僵尸进程。
2.2 剩下没有 wait 的子进程但是又没有成为僵尸进程显然就是主进程早于它退出了,它被 init 收养罢了
2.3 子进程成为了僵尸进程,但是主进程没有退出,显然就是主进程没有调用 wait 罢了。
3. 你的分析还算是对,但是你的结论却有问题,这个你还是得看我的第二点。要不然你的结论如何解释你的第一个场景呢?
这个问题挺常见的,确实得注意。用 subprocess.Popen 时,如果父进程没等子进程结束就退出了,或者没处理好子进程的退出状态,系统里就会留下僵尸进程。
核心原因就是 Popen 对象创建的子进程结束后,它的退出状态还留在系统进程表里,等着父进程来“收尸”(读取退出码)。如果你不调用 wait()、communicate() 或者设置 preexec_fn=os.setpgrp 配合信号处理,就可能出问题。
最稳的办法就是用 Popen 对象的 wait() 或者 communicate() 方法。communicate() 还会帮你管输入输出,更省心。比如:
import subprocess
proc = subprocess.Popen(['ls', '-l'])
# 等它结束,回收状态
proc.wait()
或者用 communicate() 同时处理输出:
proc = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
output, errors = proc.communicate()
# communicate() 内部已经调用了 wait()
如果你需要非阻塞地跑子进程,又不想等,可以用 signal.SIGCHLD 信号处理,或者在创建 Popen 时加上 preexec_fn=os.setpgrp,然后忽略子进程的退出信号。不过信号处理在跨平台时可能有点坑,Windows 下不灵。
还有个更简单的办法是用 subprocess.run(),这是 Python 3.5 之后推荐的,它内部就处理好了等待和资源回收,基本不会出僵尸进程:
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
总之,记得明确处理子进程的退出状态,别让它们变僵尸。
总结:记得用 wait()、communicate() 或直接上 subprocess.run()。
多谢,
不用乱想 这些都不是 python 的知识
自己看 linux 相关系统调用就明白了

