Windows中Python的缓冲与无缓冲输出

时间:2012-04-20 00:58:25

标签: python notepad++ nppexec unbuffered-output

我使用NppExec / Notepad ++来运行Python脚本,并在运行时连续刷新输出缓冲区以使用print语句更新我的控制台窗口(默认缓冲输出仅显示所有打印语句脚本完成执行后)。

This链接显示您需要做的就是使用命令python -u来获取无缓冲的输出。对于所有我的Python脚本,无论使用哪种编辑器,使用此执行模式是否有缺点?我不清楚缓冲的无缓冲输出之间的区别。

编辑:我将这个小型Python计时器脚本包含在一个示例中:

#!usr/bin/env python
import time
import threading
import sys

class Timer(threading.Thread):
    def __init__(self, seconds):
        self.runTime = seconds
        threading.Thread.__init__(self)
    def run(self):
        counter = self.runTime
        for sec in range(self.runTime):
            print counter
            time.sleep(1.0)
            counter -= 1
        print "Done."

if __name__ == '__main__':
    t = Timer(10)
    t.start()

在这种情况下,缓冲和无缓冲输出在效率方面有多大差异?

2 个答案:

答案 0 :(得分:2)

缓冲输出意味着计算机将输出假脱机到内存中的某个位置,直到累积了一定量。然后它立刻写入整个块。这比使用无缓冲输出更有效,该输出在您请求输出时立即写入输出。

缺点是你的程序会运行一点点(或很多),这取决于你写的输出量。如果他们是没有做太多输出的短程序,你不太可能注意到差异......

编辑

缓冲与无缓冲输出不仅是一个python问题。相同的概念(和术语)也适用于其他语言。在较低级别的语言中,它在某些方面变得更加重要 - 如果我使用缓冲输出在C程序中写入消息,然后我的程序因编程错误而死亡,在错误之前假脱机的任何数据,但不是写入磁盘丢失了。这不是一个问题,因为让python解释器中止一个错误是相当困难的 - 即使你的代码很糟糕,解释器仍然可以在最后清理......(除非你向它发送一个kill信号)或某事)...

答案 1 :(得分:2)

我可以想到两个缺点,但它们的重要程度取决于您的需求:

  1. 无缓冲的读写可能会慢得多;如果您一次编写一行文本文件,您的代码可能会进行数百次系统调用,要求操作系统编写该文件。根据您写入磁盘的速度,这甚至可能意味着需要从磁盘重新读取文件的最后一个块,以便使用新的最后一行重新保存文件。 (这可能很少见;但是更多的系统调用几乎总是变慢的一个因素。)

    以下是对写入速度有很大影响的系统调用次数的简单演示:

    $ cat initrd.img-2.6.38-8-generic > /dev/null
    

    第一行确保文件位于缓存中,因此仅测量输出速度。

    $ dd if=initrd.img-2.6.38-8-generic of=/tmp/out bs=16 oflag=dsync
    ^C262766+0 records in
    262766+0 records out
    4204256 bytes (4.2 MB) copied, 50.7754 s, 82.8 kB/s
    

    我放弃了等待 - 这太慢了。这是“无缓冲”,一次写入16个字节到磁盘,并确保每个写入成功,然后继续下一个。 (那是dsync - 稍后会更多。)

    $ dd if=initrd.img-2.6.38-8-generic of=/tmp/out bs=$((4096)) oflag=dsync
    3218+1 records in
    3218+1 records out
    13181130 bytes (13 MB) copied, 3.69961 s, 3.6 MB/s
    $ dd if=initrd.img-2.6.38-8-generic of=/tmp/out bs=$((4096 * 10)) oflag=dsync
    321+1 records in
    321+1 records out
    13181130 bytes (13 MB) copied, 0.471143 s, 28.0 MB/s
    

    这两个命令显示了一些缓冲的效果 - 第一个以4096字节的块写入数据,这可能是默认缓冲为您提供的。这大约比一次16字节快50倍。第二个命令是以40960字节块的形式写入数据,它的速度大约快了九倍。 (总而言之,一次写入40960字节比一次写入16字节快大约345倍。)

    如果您的数据很小,这并不重要。毕竟,无论如何都不会花费太多时间。如果您的数据很大,则可能更重要,具体取决于您一次写入的数据量以及它与基础设备的快乐“字节边界”之间的排列频率。

  2. 套接字上的某些协议可能会根据您发送的数据的 timing 更改其行为。如果您正在逐步构建数据,则可以在单个数据包中发送部分数据,而基于数据包的接收器可能无法正常处理此数据。 (除了驾驶某种类型的游戏之外,我更难想象一个基于TCP的系统存在这个问题;基于UDP的系统更容易想象有这个问题。)