如何修复subprocess.check_output()中的挂起

时间:2019-09-02 04:34:05

标签: python-3.x subprocess

我正在尝试执行以下代码,以将配置文件作为输入来运行python脚本:

try:
    process = check_output(["python", "E:/SpaceWeather/Source_codes/codes_written/tec-suite-master/tecs.py", \
                       "-c",str(cfgdirectory/'new.cfg')],stderr=STDOUT,timeout = 300)
except subprocess.CalledProcessError as e:
    print(e.output)

我以前是将Popenprocess.communicate()一起使用的,所以它是这样写的,并且一直挂着。我的脚本的设计方式使用不同的配置文件在check_output中循环,而timeout参数的目的是结束循环中需要花费太长时间的实例。但是,当我现在运行脚本时,有时它会随机挂在特定的循环实例上,我不确定为什么。超时参数似乎并没有结束进程并进入循环中的下一个迭代?

有人知道这可能正在发生吗?

注意:我们输入配置文件的脚本E:/SpaceWeather/Source_codes/codes_written/tec-suite-master/tecs.py与我的工作目录位于不同的位置,我不确定是否会有所不同。

编辑:我尝试了以下在Subprocess timeout failure看到的解决方案:

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]

,它似乎可以很好地循环运行。但是,在循环结束时,该过程不会结束,并且会无限期地挂起。如何强制该过程在循环结束时实际终止?

编辑2:我编辑了一些代码行以说明它们位于Windows平台上,并且似乎一切正常,除非其中一个进程遇到超时。此后,一切都挂起。出于某种原因,即使进程执行了应有的操作,它们也不会结束!

with Popen(["python", "E:/SpaceWeather/Source_codes/codes_written/tec-suite-master/tecs.py", \
                   "-c",str(cfgdirectory/'new.cfg')],stdout=PIPE \
                        ,shell=False) as process:
    try:   
        output = process.communicate(timeout=300)[0]

    except TimeoutExpired:
        print('Forced kill at ' + str(observationDateTime))
#        os.kill(process.pid, signal.CTRL_C_EVENT)
        subprocess.call(['taskkill', '/F', '/T', '/PID', str(p.pid)])
        output = process.communicate()[0]
        print('done')

    except Exception as e:
        print('UNKNOWN EXCEPTION, TERMINATED')
#        os.kill(process.pid, signal.CTRL_C_EVENT)
        subprocess.call(['taskkill', '/F', '/T', '/PID', str(p.pid)])
        output = process.communicate()[0]
        print('done')

在上面的代码中,当打印Forced kill at ....时,永远不会出现应遵循的done。可能是因为我正在遍历流程,因此process不断变化,因此难以终止它吗?

1 个答案:

答案 0 :(得分:1)

您处在正确的轨道上,
只需将signal.SIGINT更改为signal.SIGKILL

不能捕获,阻止或忽略信号SIGKILL和SIGSTOP。

可以捕获,阻止或忽略SIGINT。

根据问题修改了示例代码
将在2秒钟内打印“完成”
如果用SIGTERM替换SIGKILL将打印“完成”长达10秒

import os
import signal
from subprocess import Popen, PIPE, TimeoutExpired
from time import monotonic as timer

start = timer()
with Popen('bash -c "trap \\\"\\\" 9 15; sleep 10;"', shell=True, stdout=PIPE, preexec_fn=os.setsid) as process:
    try:
        output = process.communicate(timeout=1)[0]
    except TimeoutExpired:
        print("forced kill")
        os.killpg(process.pid, signal.SIGKILL) # send signal to the process group
        output = process.communicate()[0]
        print("done")