【问题标题】:How to cleanly kill subprocesses in python如何干净地杀死python中的子进程
【发布时间】:2017-06-17 02:48:21
【问题描述】:

我们正在使用 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

该进程尚未被杀死/失效。使用带有'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 中处理已失效的进程?

有没有更好的杀死进程的方法?

【问题讨论】:

  • kill 只向进程发送一个“信号”并要求它终止它的工作。但是,如果您使用-9 kill 它会被操作系统杀死。但这被认为是结束进程的不好方法。
  • kill -9subprocess.kill() 功能相同。无论我尝试用p.terminate() 干净地终止它还是用p.kill() 杀死它,它仍然最终成为僵尸进程。
  • 我使用Popen.(['ffmpeg' etc...]) 将来自本地主机的UDP 数据保存到mp3 文件中。当我通过 IDE 结束执行时,一切正常,但是当我尝试使用 Popen.terminate()Popen.wait() 通过代码本身结束它时,文件大小为 zero

标签: python linux zombie-process defunct


【解决方案1】:

这里有两个主要问题:

第一个问题:如果您使用shell=True,那么您正在杀死运行进程的shell,而不是进程本身。随着其父进程被杀死,子进程将失效/不会立即被杀死。

在您的情况下,您使用的不是内置的sleep,因此您可以删除shell=True,而Popen 将产生实际的进程ID:p.terminate() 可以工作。

大多数时候你可以(而且你应该)避免shell=True,即使它需要额外的 python 编码工作(将 2 个命令连接在一起,重定向输入/输出,所有这些情况都可以由一个或多个 @ 很好地处理987654328@ 没有 shell=True.

并且(第二个问题)如果在修复后终止时进程仍然失效,您可以致电p.wait()(来自this 问题)。似乎调用terminate 是不够的。 Popen 对象需要被垃圾回收。

【讨论】:

  • 谢谢,p.wait()p.terminate() 电话修复后!
  • 仅供参考,您可以尝试使用shell=True 看看它是否仍然有效?或者如果你得到了一个不复存在的?
  • 如果 shell=True,ps aux | grep sleep 的行为如下:User 9689 0.0 0.0 4508 796 pts/7 S+ 16:28 0:00 /bin/sh -c sleep 100 User 9690 0.0 0.0 7292 648 pts/7 S+ 16:28 0:00 sleep 100 然后发出p.kill()p.terminate() 命令。 $ ps aux| grep 'sleep' User 9690 0.0 0.0 7292 648 pts/7 S+ 16:28 0:00 sleep 100
  • 不,我认为这行不通。发出p.terminate() 命令后仍有sleep 进程在运行,kill 命令已经杀死了shell 命令(我认为!)
  • 还有其他事情吗?我使用Popen.(['ffmpeg' etc...]) 将来自本地主机的UDP 数据保存到mp3 文件中。当我通过 IDE 结束执行时,一切正常,但是当我尝试使用 Popen.terminate()Popen.wait() 通过代码本身结束它时,文件大小为 zero
【解决方案2】:

您应该在终止子进程后调用p.wait() - 以清除进程表。这应该删除僵尸进程(defunct 状态)

【讨论】:

  • 谢谢,是的,这确实解决了问题。
  • 解决了这个问题(所以+1),但前提是shell=False
  • 同意,需要shell=False,所以python没有生成shell,直接调用clone/exec
猜你喜欢
  • 2010-12-08
  • 2020-06-10
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
  • 2011-09-26
  • 2014-06-19
相关资源
最近更新 更多