关于linux:使用Python强制另一个程序的标准输出无缓冲

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),使其显式刷新其输出。在从管道读取输入文件名并打印检测到的类型的模式下使用文件时,这是必需的。因为在这种模式下,文件程序不会在完成后退出,否则输出将不会出现。

在较低的层次上考虑这个问题:输出缓冲仅仅意味着在缓冲流上执行write()会将数据复制到内存缓冲区中,直到缓冲区填满,或者(通常)直到找到换行符为止。然后,缓冲区的溢出部分或换行部分被写入底层系统级文件描述符(可以是文件、管道、套接字等)。

我不明白您将如何说服该程序从外部刷新其缓冲区。


这个问题的答案可能有助于:

python运行守护进程子进程&;read stdout

似乎也在解决同样的问题。


值得注意的是,有些程序只在认为输出不会传递给"真正的用户"(即tty)时才缓冲输出。当它们检测到它们的输出被另一个程序读取时,它们会缓冲。

TTY的模拟是期望在自动化其他进程时所做的事情之一。

有一个纯Python的Expect实现,但我不知道它处理TTY仿真有多好。


这个问题有点老了,但我认为现在可以通过使用子进程调用stdbuf和执行命令来解决您的问题。


尝试使用-u参数运行python解释器:

1
python -u myscript.py

这将强制Python使用未缓冲的stdin/stdout,这可能对您有所帮助。