使用超时的子进程:在TimeoutExpired异常后应该怎么处理?

13 浏览
0 Comments

使用超时的子进程:在TimeoutExpired异常后应该怎么处理?

如果我按照Python文档的建议使用subprocess超时=秒,它对我无效:

# 可复制粘贴的代码片段 :-)
import subprocess32 as subprocess
import datetime
now=datetime.datetime.now()
pipe=subprocess.Popen('sleep 5', shell=True, stdout=subprocess.PIPE)
try:
    pipe.communicate(timeout=1)
except subprocess.TimeoutExpired, exc:
    time_delta=datetime.datetime.now()-now
    print(time_delta)
    assert time_delta

文档建议在TimeoutExpired后使用pipe.kill()和pipe.communicate():https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate

对我来说不起作用。第二个communicate()没有立即返回。

异常:

0:00:01.001234
0:00:05.002919
Traceback (most recent call last):
  File "/home/foo/src/test_timeout.py", line 16, in 
    assert time_delta

如果我使用['sleep', '5']而不是shell=True,它就可以正常工作。

如果我不提供stdout=subprocess.PIPE,它也可以正常工作。

我猜shell不会对pipe.kill()做出反应。

解决此问题的最佳方法是什么?

0
0 Comments

问题的出现的原因是在使用subprocess模块进行子进程管理时,如果设置了超时时间,当子进程超时后会抛出TimeoutExpired异常。在处理这个异常时,一般的做法是捕获TimeoutExpired异常,然后终止已经启动的进程,再次调用.communicate()方法。

然而,问题在于代码中的pipe.kill()只会终止shell进程,而像/bin/sleep这样的子进程可能会继续运行。要解决这个问题,可以参考链接How to terminate a python subprocess launched with shell=True中的方法,来终止所有相关的子进程。

需要注意的是,如果不需要等待孙子进程的结束,可以参考链接Python subprocess .check_call vs .check_output中的方法。

感谢提供的其他StackO问题的链接,我将我的问题标记为重复问题。

0