我应该将stdout和stdin设置为在C中无缓冲吗?

时间:2016-02-06 10:27:55

标签: c buffer stdout stdin

由于有时会stdinstdout缓存printf,因此不会执行scanfgetchar。我通常使用fflush(stdout)刷新输出缓冲区,但代码因此而变得非常难以理解。如果我使用stdinstdout设置setbuf(stdin, NULL)setbuf(stdout, NULL)无缓冲,我会让我的程序表现更好还是更差?

1 个答案:

答案 0 :(得分:7)

使#include <stdio.h> int Maxmin(int a[][4], int row, int col) { int i, j, max; max = a[0][0]; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { if (a[i][j] > max) max = a[i][j]; } return max; } } void main() { int a[3][4] = { { 3, 87, 11, 23 }, { 99, 78, 19, 44 }, { 59, 60, 13, 14 } }; int num; num = Maxmin(a, 3, 4); printf("%d\n", num); } stdin完全无缓冲可以使程序在处理大量文件输入/输出时表现更差。大多数I / O请求将按字节逐个进行系统调用。

请注意,缓冲不会导致stdoutprintfscanf无法执行:getchar输出到最终目的地只能被延迟,因此输入操作通过printfscanf可能会在没有提示的情况下发生。

另请注意,将intput设置为unbuffered可能无法从终端生效,因为终端本身会通过getcharstty执行自己的缓冲。

大多数C库都有一个hack,当从ioctl读取需要从系统获取数据时会导致stdout被刷新,但是这个行为没有在C标准中指定,所以有些库没有实现它。在输入操作之前以及诸如进度表之类的暂时性消息之后添加对stdin的调用是安全的。在大多数情况下,最好让C启动程序根据与fflush(stdout);stdin流关联的系统句柄类型确定适当的缓冲策略。常见的默认值是对设备进行行缓冲,并对文件进行完全缓冲,大小为stdout

要了解潜在的性能影响,请编译这个天真的BUFSIZ程序:

ccat

时间程序执行多次复制大文件以最小化文件缓存副作用。

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

#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;
}

如你所见:

  • 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 stdin设置为无缓冲会导致程序速度减慢几乎 100
  • 使用行缓冲减慢因子 10 (因为行很短,平均9到10个字节)
  • 使用较大的缓冲区没有任何改善,时间差异不显着,
  • 天真的实现非常快,但真正的stdout实用程序使用更快的API,执行时间 6 快。

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