理解subprocess.TimeoutExpired,希望在超时后结束子进程

9

请问有人能帮我理解subprocess模块中的timeout参数是如何工作的,以及如何正确使用subprocess.TimeoutExpired异常吗?

我的用例是,我有一个主运行程序,其中包括重复运行子进程。已知子进程会不时地挂起,我希望防止此问题影响整个程序。

我想使用timeout参数来限制子进程的运行时间。但是,在下面的示例程序中,行为与我的预期不同。当运行parent.py时,它确实启动了child.py,并且我可以看到child.py的输出计数。在4秒后,parent.py确实获得了subprocess.TimeoutExpired异常,但是child.py的输出仍然在继续。这让我认为child.py进程实际上并没有被杀死。然而文档似乎暗示它将被杀死:

timeout参数传递给Popen.wait()。如果超时,子进程将被杀死,然后再次等待。在子进程终止后,TimeoutExpired异常将再次引发。

那么我该怎么解决这个问题呢?当我收到超时异常时,是否需要手动杀死子进程?

感谢您的帮助。

parent.py

#!/usr/bin/env python3

import os
import sys
import subprocess

p = subprocess.Popen("/path/to/python3 /path/to/child.py", shell=True)
try:
    p.wait(timeout=4)
except subprocess.TimeoutExpired:
    print("we got a timeout. exiting")
    sys.exit(1)

child.py

#!/usr/bin/env python3

import os
import sys
import time

for i in range(200):
    print("i is {}".format(i))
    time.sleep(1)

1
你没有参考Popen.wait()的文档,你发布的文档似乎是模块函数callcheck_outputcheck_call之一。 - mata
1
你可以使用subprocess.call()来调用子进程。如果子进程是Python脚本,最好将其作为模块导入,并使用multiprocessingfutures运行它,这样更灵活。 - jfs
2个回答

2

看起来您需要添加一个调用:

p.terminate()

根据当前的文档,在您的父进程中的sys.exit之前,您引用的部分仅适用于subprocess.call,而这不是您此处使用的内容。请注意保留HTML标签。

1

从文档中获取:

如果进程在超时秒后没有终止,则引发TimeoutExpired异常。捕获此异常并重试等待是安全的。

这意味着您可以捕获异常,除非您杀死进程(或Python),否则进程将继续执行。在您的情况下,因为您正在进行

sys.exit(1)

然后Python本身将被终止,Popen对象将被垃圾回收。

1
退出父进程并不会杀死其子进程。 - jfs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接