我在编写脚本来启动本地 JBoss 实例时遇到了一个奇怪的问题。
我的代码看起来像这样:
with open("/var/run/jboss/jboss.pid", "wb") as f:
process = subprocess.Popen(["/opt/jboss/bin/standalone.sh", "-b=0.0.0.0"])
f.write(str(process.pid))
try:
process.wait()
except KeyboardInterrupt:
process.kill()
应该很容易理解,在运行时将 PID 写入文件,一旦我得到
KeyboardInterrupt
,就杀死子进程。问题是在我发送 kill 信号后 JBoss 继续在后台运行,因为该信号似乎没有传播到由
standalone.sh
启动的 Java 进程。我喜欢使用 Python 编写系统管理脚本的想法,但是有很多像这样的奇怪边缘情况,如果我用 Bash 编写它,一切都会正常工作™。
当我得到
KeyboardInterrupt
时,如何杀死整个子进程树? 最佳答案
您可以使用 psutil
库执行此操作:
import psutil
#..
proc = psutil.Process(process.pid)
for child in proc.children(recursive=True):
child.kill()
proc.kill()
据我所知,
subprocess
模块不提供任何 API 函数来检索子进程产生的子进程,os
模块也不提供。杀死进程的更好方法可能是以下内容:
proc = psutil.Process(process.pid)
procs = proc.children(recursive=True)
procs.append(proc)
for proc in procs:
proc.terminate()
gone, alive = psutil.wait_procs(procs, timeout=1)
for p in alive:
p.kill()
这将使进程有机会正确终止,当超时结束时,剩余的进程将被杀死。
请注意,
psutil
还提供了一个 Popen
类,该类具有与 subprocess.Popen
相同的接口(interface)以及 psutil.Process
的所有额外功能。您可能只想使用它而不是 subprocess.Popen
。它也更安全,因为 psutil
会检查进程终止时 PID 不会被重用,而 subprocess
则不会。关于python - 在 KeyboardInterrupt 上杀死一系列子进程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24894986/