子进程超时失败 [英] Subprocess timeout failure

查看:123
本文介绍了子进程超时失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在子进程上使用超时

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() 带超时本质上是:

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)

有两个问题:

  • [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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆