子进程超时失败

发布于 2021-01-29 19:07:55

我想在子流程上使用超时

 from subprocess32 import check_output
 output = check_output("sleep 30", shell=True, timeout=1)

不幸的是,尽管这会引起超时错误,但它会在30秒后发生。看来check_output无法中断shell命令。

我该如何在Python方面阻止这种情况?我怀疑subprocess32无法杀死超时的进程。

关注者
0
被浏览
50
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    check_output()超时基本上是

    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与.check_output
    • process.kill()可能不会杀死整个进程树,请参阅如何终止用shell = True启动的python子进程

    它导致您观察到的行为:TimeoutExpired一秒钟发生,shell被杀死,但check_output()仅在孙sleep进程退出后30秒内返回。

    要变通解决此问题,请杀死整个进程树(属于同一组的所有子进程):

    #!/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
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看