为什么子进程的标准输出(重定向到无缓冲文件)会被缓冲?

11 投票
2 回答
2565 浏览
提问于 2025-04-16 17:11

来自 http://docs.python.org/library/functions.html#open

可选的 bufsize 参数指定了文件的缓冲区大小:0 表示不使用缓冲,1 表示按行缓冲,其他正数值则表示使用大约这个大小的缓冲区。负数的 bufsize 表示使用系统默认的设置,通常对于终端设备是按行缓冲,而对于其他文件则是完全缓冲。如果不指定这个参数,就会使用系统默认值。

我在下面传入了 0 作为 bufsize,但在运行 main_process 时,如果不使用 flush(),文件里没有任何输出。
这是为什么呢?

# --------------------------------- sub_process.py
import sys
import time

if __name__ == '__main__':
    print 'printed from redirect.py'
    # why is the following flush() needed? 'std-output' is (?) unbuffered...
    sys.stdout.flush() 
    time.sleep(6)


# --------------------------------- main_process.py
import subprocess
import time

if __name__ == '__main__':
    p = subprocess.Popen(
        ['python', 'sub_process.py'],
        stdout=open('std-output', 'w', 0))
    time.sleep(3)
    p.terminate()

2 个回答

8

在使用Python的时候,可以加上一个“-u”这个标志,比如:

if __name__ == '__main__':
    p = subprocess.Popen(
        ['python', '-u', 'sub_process.py'],
        stdout=open('std-output', 'w'))
    time.sleep(3)
    p.terminate()
5

扩展一下Magnus Skog的解决方案(顺便说一下,赞一个 :)):

基本上发生的事情是,当子进程要创建一个新进程时,它会把标准输出(stdout)的设置复制到新进程的标准输出上(文件编号 = 1),这个过程是通过os.dup2来实现的(可以查看subprocess.Popen._execute_child)。这样做会保持无缓冲状态(dup2的作用就是这样),到这里一切都很好。但是,当Python在子进程中启动时,如果没有看到-u这个标志,Python默认会把标准输出的缓冲设置为行缓冲(可以查看main python function),这就会覆盖你之前设置的缓冲标志。

希望这能更好地解释你所看到的行为。

撰写回答