【Linux基础知识】的基本操作方法(二)

[解决方案1]:

一共有三层缓冲,需要限制这三层才能保证获取到实时数据:

用 stdbuf 命令包装子进程执行(在 Linux 上)(例如运行 [‘stdbuf’, ‘-oL’] + cmd 而不仅仅是 cmd),或者(如果你有能力这样做)更改程序本身要么显式更改标准输出上的缓冲(例如,使用 setvbuf 用于 C/C++ 代码以将标准输出全局切换到行缓冲模式,而不是输出到非 tty 时使用的默认块缓冲)或在关键输出(例如,fflush(stdout); 对于 C/C++,fileobj.flush() 对于 Python 等)将程序缓冲为面向行的模式(或添加 fflushs);否则,一切都会卡在子进程的用户模式缓冲区中间。

将 bufsize=0 添加到 Popen 参数(可能不需要,因为您没有向标准输入发送任何内容,但无害),因此它不缓冲所有管道句柄。如果 Popen 处于 text=True 模式,则切换到 bufsize=1(行缓冲,而非无缓冲)。

将 flush=True 添加到 print 参数(如果您连接到终端,行缓冲将为您刷新它,因此只有在您将 stdout 传输到文件时才有意义),或显式调用 sys. stdout.flush ( )。

在这三者之间,您应该能够保证没有数据卡在用户模式缓冲区中等待;如果子流程至少有一行输出,它会立即到达您,并且由它触发的任何输出也将立即出现。在大多数情况下,第 1 项是最难的(当您无法使用 stdbuf,或者进程在内部重新配置自己的缓冲区并撤消 stdbuf 的影响,并且您无法修改进程可执行文件来修复它时);你可以完全控制 #2 和 #3,但 #1 可能不在你的控制范围内。

【讨论】:

[解决方案2]:

这是我用于相同目的的代码:

def run_command(command, **kwargs):
    """Run a command while printing the live output"""
    process = subprocess.Popen(
        command,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        **kwargs,
    )
    while True:   # Could be more pythonic with := in Python3.8+
        line = process.stdout.readline()
        if not line and process.poll() is not None:
            break
        print(line.decode(), end='')

使用示例如下:

run_command(['git', 'status'], cwd=Path(__file__).parent.absolute())

【讨论】:

© 版权声明
THE END
喜欢就支持一下吧
点赞195 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片