用C或Python中的popen绕过子进程输出的缓冲

Gea*_*phy 12 c python buffer pipe

我有一个关于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)
Run Code Online (Sandbox Code Playgroud)

以下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()
Run Code Online (Sandbox Code Playgroud)

调整操作系统的路径.在此配置中运行时,尽管popen命令的缓冲区大小设置为0(无论如何都是默认值),但输出不会以1024块显示,而是以4096块显示.任何人都可以告诉我如何改变这种行为吗?有什么方法可以强迫操作系统以与从控制台运行时相同的方式处理分叉进程的输出,即只需通过数据提供数据没有缓冲?

Ale*_*lli 16

通常,标准C运行时库(代表几乎每个系统上的每个程序运行,或多或少;-)检测stdout是否是终端; 如果没有,它会缓冲输出(与无缓冲输出相比,这可以获得巨大的效率).

如果您正在控制正在编写的程序,您可以(作为另一个答案建议)连续刷新stdout,或者(如果可行的话更优雅)尝试强制stdout无缓冲,例如通过使用-u命令行标志运行Python :

-u     : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)
         see man page for details on internal buffering relating to '-u'
Run Code Online (Sandbox Code Playgroud)

(手册页添加的内容是提到stdin和二进制模式的问题[s]).

如果您不能或不想触摸-u正在阅读的程序上的程序,或者刚刚阅读的程序不太可能有帮助(最重要的缓冲是作者的stdout上发生的缓冲,而不是读者的标准).另一种方法是通过pty标准库模块或更高级别的第三方pexpect模块(或者,对于Windows,其端口)欺骗作者相信它正在写入终端(即使事实上它正在写入另一个程序!)wexpect).