如何干净地杀死 python 中的子进程
How to cleanly kill subprocesses in python
我们正在使用 python 流程来管理较长的 运行 python 子流程。有时需要终止子进程。 kill 命令不会完全杀死进程,只会使其失效。
运行 以下脚本演示了此行为。
import subprocess
p = subprocess.Popen(['sleep', '400'], stdout=subprocess.PIPE, shell=False)
或
p = subprocess.Popen('sleep 400', stdout=subprocess.PIPE, shell=True)
将创建一个子进程。
p.terminate()
p.kill()
对进程没有任何作用。 ps aux | grep sleep
展示
$ ps aux| grep 'sleep'
User 8062 0.0 0.0 7292 764 pts/7 S 14:53 0:00 sleep 400
该进程尚未 killed/made 失效。使用带有 'kill'
和 pid
作为参数的 subprocess.call()
函数将发出 kill 命令。
subprocess.call(['kill', str(p.pid)])
这将终止该进程,但它现在已经不存在了。
$ ps aux | grep 'sleep'
User 8062 0.0 0.0 0 0 pts/7 Z+ 14:51 0:00 [sleep] <defunct>
如果队列 运行 足够长,它最终会达到其最大进程数,还是最终会回收已停用的进程并且没问题?
如果答案是前者,我如何在不杀死父进程的情况下处理 python 中的已失效进程?
是否有更好的终止进程的方法?
这里有两个主要问题:
第一个问题:如果您正在使用 shell=True
,那么您将终止 shell 运行 进程,而不是过程本身。父进程被杀死后,子进程就会失效/不会立即被杀死。
在您的情况下,您使用的是 sleep
而不是 built-in,因此您可以删除 shell=True
,而 Popen
将产生实际的进程 ID: p.terminate()
可以。
大多数时候你可以(而且你应该)避免 shell=True
,即使它需要额外的 python 编码工作(将 2 个命令连接在一起,重定向 input/output,所有这些案件可以由一个或几个人很好地处理 Popen
without shell=True
.
并且(第二个问题)如果在该修复后终止时进程仍然不存在,您可以调用 p.wait()
(来自 this 问题)。似乎调用 terminate
是不够的。 Popen
对象需要进行垃圾回收。
您应该在终止子进程后调用 p.wait()
- 用于清除进程 table。那应该删除僵尸进程(处于 defunct
状态)
我们正在使用 python 流程来管理较长的 运行 python 子流程。有时需要终止子进程。 kill 命令不会完全杀死进程,只会使其失效。
运行 以下脚本演示了此行为。
import subprocess
p = subprocess.Popen(['sleep', '400'], stdout=subprocess.PIPE, shell=False)
或
p = subprocess.Popen('sleep 400', stdout=subprocess.PIPE, shell=True)
将创建一个子进程。
p.terminate()
p.kill()
对进程没有任何作用。 ps aux | grep sleep
$ ps aux| grep 'sleep'
User 8062 0.0 0.0 7292 764 pts/7 S 14:53 0:00 sleep 400
该进程尚未 killed/made 失效。使用带有 'kill'
和 pid
作为参数的 subprocess.call()
函数将发出 kill 命令。
subprocess.call(['kill', str(p.pid)])
这将终止该进程,但它现在已经不存在了。
$ ps aux | grep 'sleep'
User 8062 0.0 0.0 0 0 pts/7 Z+ 14:51 0:00 [sleep] <defunct>
如果队列 运行 足够长,它最终会达到其最大进程数,还是最终会回收已停用的进程并且没问题?
如果答案是前者,我如何在不杀死父进程的情况下处理 python 中的已失效进程?
是否有更好的终止进程的方法?
这里有两个主要问题:
第一个问题:如果您正在使用 shell=True
,那么您将终止 shell 运行 进程,而不是过程本身。父进程被杀死后,子进程就会失效/不会立即被杀死。
在您的情况下,您使用的是 sleep
而不是 built-in,因此您可以删除 shell=True
,而 Popen
将产生实际的进程 ID: p.terminate()
可以。
大多数时候你可以(而且你应该)避免 shell=True
,即使它需要额外的 python 编码工作(将 2 个命令连接在一起,重定向 input/output,所有这些案件可以由一个或几个人很好地处理 Popen
without shell=True
.
并且(第二个问题)如果在该修复后终止时进程仍然不存在,您可以调用 p.wait()
(来自 this 问题)。似乎调用 terminate
是不够的。 Popen
对象需要进行垃圾回收。
您应该在终止子进程后调用 p.wait()
- 用于清除进程 table。那应该删除僵尸进程(处于 defunct
状态)