如何使用subprocess模块终止(或避免)僵尸进程
当我在一个Python脚本里启动另一个Python脚本时,使用了一个叫做subprocess的模块。这个时候会出现一个“僵尸进程”,当子进程完成后就会变成这样。我无法单独结束这个子进程,除非我把父脚本也结束掉。
有没有办法在不结束父脚本的情况下,单独结束这个子进程呢?我知道可以用wait()来做到这一点,但我需要用no_wait()来运行我的脚本。
11 个回答
17
如果你用del命令删除一个子进程对象,这样会强制进行垃圾回收。结果就是这个子进程对象会被删除,然后那些无用的进程也会消失,而不会影响到你的解释器。你可以先在Python的命令行界面试试看。
23
如果不使用 Popen.communicate()
或 call()
,就会出现僵尸进程。
如果你不需要命令的输出,可以使用 subprocess.call()
:
>>> import subprocess
>>> subprocess.call(['grep', 'jdoe', '/etc/passwd'])
0
如果输出很重要,你应该使用 Popen()
和 communicate()
来获取标准输出和错误输出。
>>> from subprocess import Popen, PIPE
>>> process = Popen(['ls', '-l', '/tmp'], stdout=PIPE, stderr=PIPE)
>>> stdout, stderr = process.communicate()
>>> stderr
''
>>> print stdout
total 0
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 bar
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 baz
-rw-r--r-- 1 jdoe jdoe 0 2010-05-03 17:05 foo
31
僵尸进程并不是真正的进程;它只是进程表中的一个残留条目,直到父进程请求子进程的返回代码。实际上,那个进程已经结束,不再需要其他资源,只需要在进程表中的这个条目。
为了更好地帮助你,我们可能需要更多关于你运行的进程的信息。
不过,如果你的Python程序知道子进程什么时候结束(比如通过读取完子进程的输出数据),那么你可以安全地调用process.wait()
:
import subprocess
process= subprocess.Popen( ('ls', '-l', '/tmp'), stdout=subprocess.PIPE)
for line in process.stdout:
pass
subprocess.call( ('ps', '-l') )
process.wait()
print("after wait")
subprocess.call( ('ps', '-l') )
示例输出:
$ python so2760652.py
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 501 21328 21326 0 80 0 - 1574 wait pts/2 00:00:00 bash
0 S 501 21516 21328 0 80 0 - 1434 wait pts/2 00:00:00 python
0 Z 501 21517 21516 0 80 0 - 0 exit pts/2 00:00:00 ls <defunct>
0 R 501 21518 21516 0 80 0 - 608 - pts/2 00:00:00 ps
after wait
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 501 21328 21326 0 80 0 - 1574 wait pts/2 00:00:00 bash
0 S 501 21516 21328 0 80 0 - 1467 wait pts/2 00:00:00 python
0 R 501 21519 21516 0 80 0 - 608 - pts/2 00:00:00 ps
否则,你可以把所有子进程放在一个列表里,然后不时地用.poll
来检查它们的返回代码。在每次检查后,记得从列表中移除返回代码不是None
(也就是已经结束的进程)的子进程。