python-3.x - 如何修复 subprocess.check_output() 中的挂起

标签 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 不断变化,因此很难终止它?

最佳答案

你在正确的轨道上,
只需将 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")

关于python-3.x - 如何修复 subprocess.check_output() 中的挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57751471/

相关文章:

python - 碰撞检测如何?

python - 如何迭代多个级别和值数组的字典

python - 即使 stdin 不是终端,也从 Python 子进程向 stdin 发送命令?

python - 从 subprocess.Popen 异步读取标准输出

string - 将八位字节字符串转换为 Unicode 字符串,Python 3

python - 如何从使用python从openCV获得的颜色检测结果区域获取屏幕坐标?

python - 尝试安装 python 时出现错误

python - 在 django View 中 fork 一个进程

python - 如何在 Python 中终止我的子进程

mysql - 为什么 Python 子进程不能像预期的那样使用 named_pipe?