【发布时间】:2016-02-06 10:27:55
【问题描述】:
由于stdin 和stdout 缓冲,有时printf、scanf 和getchar 不会执行。我通常使用fflush(stdout) 刷新输出缓冲区,但代码可能因此变得非常不可读。如果我使用setbuf(stdin, NULL) 和setbuf(stdout, NULL) 设置stdin 和stdout 无缓冲,我会让我的程序性能更好还是更差?
【问题讨论】:
由于stdin 和stdout 缓冲,有时printf、scanf 和getchar 不会执行。我通常使用fflush(stdout) 刷新输出缓冲区,但代码可能因此变得非常不可读。如果我使用setbuf(stdin, NULL) 和setbuf(stdout, NULL) 设置stdin 和stdout 无缓冲,我会让我的程序性能更好还是更差?
【问题讨论】:
如果您的程序处理来自文件的大量输入/输出,则使stdin 或stdout 完全无缓冲会使您的程序性能更差。大多数 I/O 请求将被逐字节分解为系统调用。
注意缓冲不会导致printf、scanf和getchar不被执行:printf输出到最终目的地可以延迟,所以通过scanf或getchar的输入操作可能会在没有提示的情况下发生。
另请注意,将 intput 设置为无缓冲可能对终端无效,因为终端本身执行通过 stty 或 ioctl 控制的自己的缓冲。
大多数 C 库都有一个 hack,导致在从 stdin 读取需要从系统获取数据时刷新 stdout,但 C 标准中没有指定此行为,因此某些库没有实现它。在输入操作之前以及在进度条等临时消息之后添加对fflush(stdout); 的调用是安全的。对于大多数目的,最好让 C 启动根据与stdin 和stdout 流相关联的系统句柄类型来确定适当的缓冲策略。常见的默认设置是对设备进行行缓冲,对文件进行完全缓冲,大小为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
如你所见:
stdin 和stdout 设置为无缓冲会导致程序速度降低几乎100,cat 实用程序使用更快的 API,执行时间快 6 倍。作为结论:不要将 stdin 和 stdout 设置为无缓冲,即使是中等大小的文件也会显着影响性能。
【讨论】: