Force another program's standard output to be unbuffered using Python
python脚本控制Linux上的外部应用程序,通过管道将输入传递到外部应用程序stdin,并通过管道从外部应用程序stdout读取输出。
问题在于,对管道的写入是由块缓冲的,而不是由行缓冲的,因此在控制脚本接收数据输出(例如外部应用程序中的printf)之前,会发生延迟。
无法更改外部应用程序以添加显式fflush(0)调用。
如何将python标准库的pty模块与子进程模块一起使用来实现这一点?
您可以使用PTY通过以下方式解决此问题:
- 创建一个PTY主/从对;
- 将子进程的stdin、stdout和stderr连接到pty从设备;
- 读写家长的私人教师。
这样做是可能的,但我能想到的唯一解决方案是相当复杂、不可移植,而且可能充满了有问题的细节。可以使用ld_preload使外部应用程序加载一个动态库,该动态库包含一个调用setvbuf以取消缓冲stdout的构造函数。您可能还希望在库中包装setvbuf,以防止应用程序显式缓冲自己的stdout。你需要包装fwrite和printf,这样它们在每次调用时都会刷新。编写.so以进行预加载将使您脱离python。
我认为这是不可能的。如果源应用程序不刷新其传出缓冲区,则在缓冲区溢出并强制刷新之前,数据不会到达该进程之外。
请注意,一个建立良好的命令(如file)如何具有一个选项(-n),使其显式刷新其输出。在从管道读取输入文件名并打印检测到的类型的模式下使用文件时,这是必需的。因为在这种模式下,文件程序不会在完成后退出,否则输出将不会出现。
在较低的层次上考虑这个问题:输出缓冲仅仅意味着在缓冲流上执行
我不明白您将如何说服该程序从外部刷新其缓冲区。
这个问题的答案可能有助于:
python运行守护进程子进程&;read stdout
似乎也在解决同样的问题。
值得注意的是,有些程序只在认为输出不会传递给"真正的用户"(即tty)时才缓冲输出。当它们检测到它们的输出被另一个程序读取时,它们会缓冲。
TTY的模拟是期望在自动化其他进程时所做的事情之一。
有一个纯Python的Expect实现,但我不知道它处理TTY仿真有多好。
这个问题有点老了,但我认为现在可以通过使用子进程调用stdbuf和执行命令来解决您的问题。
尝试使用-u参数运行python解释器:
1 | python -u myscript.py |
这将强制Python使用未缓冲的stdin/stdout,这可能对您有所帮助。