【问题标题】:Should I set stdout and stdin to be unbuffered in C?我应该在 C 中将 stdout 和 stdin 设置为无缓冲吗?
【发布时间】:2016-02-06 10:27:55
【问题描述】:

由于stdinstdout 缓冲,有时printfscanfgetchar 不会执行。我通常使用fflush(stdout) 刷新输出缓冲区,但代码可能因此变得非常不可读。如果我使用setbuf(stdin, NULL)setbuf(stdout, NULL) 设置stdinstdout 无缓冲,我会让我的程序性能更好还是更差?

【问题讨论】:

    标签: c buffer stdout stdin


    【解决方案1】:

    如果您的程序处理来自文件的大量输入/输出,则使stdinstdout 完全无缓冲会使您的程序性能更差。大多数 I/O 请求将被逐字节分解为系统调用。

    注意缓冲不会导致printfscanfgetchar不被执行:printf输出到最终目的地可以延迟,所以通过scanfgetchar的输入操作可能会在没有提示的情况下发生。

    另请注意,将 intput 设置为无缓冲可能对终端无效,因为终端本身执行通过 sttyioctl 控制的自己的缓冲。

    大多数 C 库都有一个 hack,导致在从 stdin 读取需要从系统获取数据时刷新 stdout,但 C 标准中没有指定此行为,因此某些库没有实现它。在输入操作之前以及在进度条等临时消息之后添加对fflush(stdout); 的调用是安全的。对于大多数目的,最好让 C 启动根据与stdinstdout 流相关联的系统句柄类型来确定适当的缓冲策略。常见的默认设置是对设备进行行缓冲,对文件进行完全缓冲,大小为BUFSIZ

    要了解潜在的性能影响,请编译这个幼稚的ccat 程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(int argc, char *argv[]) {
        int c, size;
    
        if (argc > 1) {
            if (!strcmp(argv[1], "BUFSIZ"))
                size = BUFSIZ;
            else
                size = strtol(argv[1], NULL, 0);
    
            if (size == 0) {
                /* make stdin and stdout unbuffered */
                setvbuf(stdin, NULL, _IONBF, 0);
                setvbuf(stdout, NULL, _IONBF, 0);
            } else
            if (size > 0) {
                /* make stdin and stdout fully buffered */
                setvbuf(stdin, NULL, _IOFBF, size);
                setvbuf(stdout, NULL, _IOFBF, size);
            } else {
                /* make stdin and stdout line buffered */
                setvbuf(stdin, NULL, _IOLBF, -size);
                setvbuf(stdout, NULL, _IOLBF, -size);
            }
        }
        while ((c = getchar()) != EOF) {
            putchar(c);
        }
        return 0;
    }
    

    定时程序执行多次复制一个大文件以最大程度地减少文件缓存的副作用。

    在 Debian linux 机器上,我得到了 3.8MB 文本文件的这些时间:

    chqrlie@linux:~/dev/stackoverflow$ time wc w
     396684  396684 3755392 w
    real    0m0.072s
    user    0m0.068s
    sys     0m0.000s
    
    chqrlie@linux:~/dev/stackoverflow$ time cat < w > ww
    real    0m0.008s
    user    0m0.000s
    sys     0m0.004s
    
    chqrlie@linux:~/dev/stackoverflow$ time ./ccat < w > ww
    real    0m0.060s
    user    0m0.056s
    sys     0m0.000s
    
    chqrlie@linux:~/dev/stackoverflow$ time ./ccat 0x100000 < w > ww
    real    0m0.060s
    user    0m0.058s
    sys     0m0.000s
    
    chqrlie@linux:~/dev/stackoverflow$ time ./ccat 0 < w > ww
    real    0m5.326s
    user    0m0.632s
    sys     0m4.684s
    
    chqrlie@linux:~/dev/stackoverflow$ time ./ccat -0x1000 < w > ww
    real    0m0.533s
    user    0m0.104s
    sys     0m0.428s
    

    如你所见:

    • stdinstdout 设置为无缓冲会导致程序速度降低几乎100
    • 使用行缓冲会减慢 10 倍(因为行很短,平均 9 到 10 个字节)
    • 使用更大的缓冲区并没有显示任何改进,时间差异并不显着,
    • 简单的实现相当快,但真正的 cat 实用程序使用更快的 API,执行时间快 6 倍。

    作为结论:不要将 stdinstdout 设置为无缓冲,即使是中等大小的文件也会显着影响性能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-04
      • 1970-01-01
      • 2019-03-30
      相关资源
      最近更新 更多