强制第三方程序在通过子进程调用时刷新其输出

Force a 3rd-party program to flush its output when called through subprocess

提问人:QuantumChris 提问时间:7/22/2019 更新时间:7/25/2019 访问量:161

问:

我正在使用第三方 python 模块,该模块通常通过终端命令调用。当通过终端命令调用时,它有一个详细的选项,可以实时打印到终端。

然后我有另一个python程序,它通过子进程调用第三方程序。不幸的是,当通过子进程调用时,终端输出不再刷新,并且仅在完成时返回(该过程需要数小时,因此我希望实时进度)。

我可以看到第三方模块的源代码,它没有将打印设置为刷新,例如.有没有办法在不编辑第三方源代码的情况下强制刷新我的模块?此外,我可以将此输出发送到日志文件(再次实时)吗?print('example', flush=True)

感谢您的帮助。

python-3.x 日志记录 终端 子进程

评论

0赞 blues 7/22/2019
我认为这回答了你的问题:stackoverflow.com/questions/4417546/......
0赞 QuantumChris 7/22/2019
@blues 很遗憾没有。由于第三方软件不会刷新输出,因此使用此方法也不会刷新输出。

答:

1赞 JohanL 7/25/2019 #1

问题很可能是,如果在终端中或作为管道的一部分以交互方式运行,则许多程序的工作方式可能会有所不同(即称为 using )。它与 Python 本身关系不大,但与 Unix/Linux 架构关系更大。subprocess

如您所指出的,即使在管道中运行时,也可以强制程序刷新,但它需要通过手动应用调用来更改源代码。stdoutstdout.flush

打印到屏幕上的另一种方法是“欺骗”程序,使其认为它正在与交互式终端一起使用,使用所谓的伪终端。Python 标准库中有一个支持模块,即 .使用 that,您不会显式调用 (or or ...)。相反,您必须使用 pty.spawn 调用:ptysubprocess.runPopen

def prout(fd):
    data = os.read(fd, 1024)
    while(data):
        print(data.decode(), end="")
        data = os.read(fd, 1024)

pty.spawn("./callee.py", prout)

可以看出,这需要一个特殊的处理功能。在上面,我只是将其打印到终端,但当然也可以对文本执行其他操作(例如日志或解析......stdout

欺骗程序的另一种方法是使用称为 .Unbuffer 将你的脚本作为输入,并让程序思考(就像调用一样)从终端调用。如果已安装或允许您将其安装在您的系统上(它是软件包的一部分),这可以说是更简单。然后,您所要做的就是将您的呼叫更改为unbufferptyunbufferexpectsubprocess

p=subprocess.Popen(["unbuffer", "./callee.py"], stdout=subprocess.PIPE)

然后当然像往常一样处理输出,例如使用一些代码,例如

for line in p.stdout:
    print(line.decode(), end="")
print(p.communicate()[0].decode(), end="")

或类似。但是最后一部分我认为您已经介绍了,因为您似乎正在对输出做一些事情。

评论

0赞 QuantumChris 7/25/2019
感谢您的回复。我们不能保证用户会取消缓冲,所以我尝试了 pty 解决方案。不幸的是,该命令在运行 pty 时返回权限被拒绝,所以我认为我们将不得不放弃它。我们将研究通过第三方软件获取拉取请求,以更改其代码。