用C或Python中的popen绕过子进程输出的缓冲
题
我有一个关于popen(和所有相关函数)的一般性问题,适用于所有操作系统,当我编写python脚本或一些c代码并从控制台运行生成的可执行文件(win或linux)时,我可以立即查看流程的输出。但是,如果我运行与分支进程相同的可执行文件,并将其stdout重定向到管道,则输出缓冲到某处,通常最多为4096字节,然后将其写入父进程可以读取的管道。
以下python脚本将以1024字节的块为单位生成输出
import os, sys, time
if __name__ == "__main__":
dye = '@'*1024
for i in range (0,8):
print dye
time.sleep(1)
以下python脚本将执行上一个脚本,并在输出到管道时逐字节地读取输出
import os, sys, subprocess, time, thread
if __name__ == "__main__":
execArgs = ["c:\\python25\\python.exe", "C:\\Scripts\\PythonScratch\\byte_stream.py"]
p = subprocess.Popen(execArgs, bufsize=0, stdout=subprocess.PIPE)
while p.returncode == None:
data = p.stdout.read(1)
sys.stdout.write(data)
p.poll()
调整操作系统的路径。在此配置中运行时,尽管popen命令的缓冲区大小设置为0(无论如何都是默认值),但输出不会以1024块显示,而是以4096块显示。任何人都可以告诉我如何改变这种行为吗?有没有什么方法可以强制操作系统以与从控制台运行时相同的方式处理分叉进程的输出?即,只需通过数据提供数据没有缓冲?
解决方案
通常,标准C运行时库(代表几乎每个系统上的每个程序运行,或多或少;-)检测stdout是否是终端;如果没有,它会缓冲输出(与无缓冲输出相比,这可以获得巨大的效率)。
如果您正在控制正在编写的程序,您可以(作为另一个答案建议)连续刷新标准输出,或者(如果可行的话更优雅)尝试强制标准输出无缓冲,例如通过使用 -u
命令行标志运行Python:
-u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)
see man page for details on internal buffering relating to '-u'
(手册页添加的内容是提到stdin和二进制模式的问题[s])。
如果您不能或不想触摸正在编写的程序,那么刚刚阅读的程序中的 -u
等不太可能有所帮助(最重要的缓冲是一个发生在作家的stdout上,而不是读者的stdin上的那个。另一种方法是通过 pty
标准库模块或更高级别的第三方来欺骗作者相信它正在写入终端(即使事实上它正在写入另一个程序!)。 href =“http://pexpect.sourceforge.net/pexpect.html”rel =“noreferrer”> pexpect 模块(或者,对于Windows,其端口 wexpect )。
其他提示
这是正确的,适用于Windows和Linux(可能还有其他系统), popen()
和 fopen()
。如果要在4096字节之前调度输出缓冲区,请使用 fflush()
(在C上)或 sys.stdout.flush()
(Python)。