子进程超时失败 [英] Subprocess timeout failure
问题描述
我想在子进程上使用超时
I want to use a timeout on a subprocess
from subprocess32 import check_output
output = check_output("sleep 30", shell=True, timeout=1)
不幸的是,虽然这会引发超时错误,但它会在 30 秒后发生.好像check_output不能中断shell命令.
Unfortunately, whilst this raises a timeout error, it does so after 30 seconds. It seems that check_output cannot interrupt the shell command.
我可以在 Python 方面做些什么来阻止这种情况?我怀疑 subprocess32 未能杀死超时进程.
What can I do on on the Python side to stop this? I suspect that subprocess32 fails to kill the timed out process.
推荐答案
check_output()
with timeout is essentially:
with Popen(*popenargs, stdout=PIPE, **kwargs) as process:
try:
output, unused_err = process.communicate(inputdata, timeout=timeout)
except TimeoutExpired:
process.kill()
output, unused_err = process.communicate()
raise TimeoutExpired(process.args, timeout, output=output)
有两个问题:
- [第二个]
.communicate()
可能会等待后代进程,而不仅仅是直接子进程,参见 Python 子进程 .check_call vs.check_output process.kill()
可能不会杀死整个进程树,请参阅如何终止 python 子进程以 shell=True 启动
- [the second]
.communicate()
may wait for descendant processes, not just for the immediate child, see Python subprocess .check_call vs .check_output process.kill()
might not kill the whole process tree, see How to terminate a python subprocess launched with shell=True
它导致您观察到的行为:TimeoutExpired
在一秒钟内发生,shell 被杀死,但 check_output()
仅在孙子之后 30 秒内返回sleep
进程退出.
It leads to the behaviour that you observed: the TimeoutExpired
happens in a second, the shell is killed, but check_output()
returns only in 30 seconds after the grandchild sleep
process exits.
要解决这些问题,请终止整个进程树(属于同一组的所有子进程):
To workaround the issues, kill the whole process tree (all subprocesses that belong to the same group):
#!/usr/bin/env python3
import os
import signal
from subprocess import Popen, PIPE, TimeoutExpired
from time import monotonic as timer
start = timer()
with Popen('sleep 30', shell=True, stdout=PIPE, preexec_fn=os.setsid) as process:
try:
output = process.communicate(timeout=1)[0]
except TimeoutExpired:
os.killpg(process.pid, signal.SIGINT) # send signal to the process group
output = process.communicate()[0]
print('Elapsed seconds: {:.2f}'.format(timer() - start))
输出
Elapsed seconds: 1.00
这篇关于子进程超时失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!