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

Bor*_*vić 4 c buffer stdin stdout

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

chq*_*lie 7

制作stdinstdout完全无缓冲可以使您的程序在处理大量文件输入/输出时表现更差.大多数I/O请求将按字节逐个进行系统调用.

注意,缓冲不引起printf,scanf并且getchar不被执行:printf输出到最终目标可以只被延迟,所以通过输入操作scanfgetchar不带提示,可能会发生.

另请注意,将intput设置为unbuffered可能无法从终端生效,因为终端本身通过stty或执行自己的缓冲控制ioctl.

大多数C库都有一个hack导致stdout在读取时刷新stdin需要从系统获取数据,但是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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

如你看到的:

  • 设置stdinstdout无缓冲导致程序减速几乎100,
  • 使用行缓冲减慢10倍(因为行很短,平均9到10个字节)
  • 使用较大的缓冲区没有任何改善,时序差异不显着,
  • 天真的实现非常快,但真正的cat实用程序使用更快的API,执行时间快了6倍.

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