2016-02-06 81 views
3

由于stdinstdout缓冲有时printf,scanfgetchar不执行。我通常使用fflush(stdout)刷新输出缓冲区,但由于这种情况,代码可能变得非常不可读。如果我使用setbuf(stdin, NULL)setbuf(stdout, NULL)来设置stdinstdout无缓冲区,我会让我的程序表现更好还是更差?我应该设置标准输出和标准输入缓冲在C?

回答

6

制作stdinstdout完全无缓冲会使您的程序在处理大量来自和去往文件的输入/输出时性能更差。大多数I/O请求将在逐字节的基础上被分解为系统调用。

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

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

大多数C库有一个黑客,导致stdoutstdin需要从系统中获取数据时被刷新,但这种行为没有在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的文本文件:

[email protected]:~/dev/stackoverflow$ time wc w 
396684 396684 3755392 w 
real 0m0.072s 
user 0m0.068s 
sys  0m0.000s 

[email protected]:~/dev/stackoverflow$ time cat <w> ww 
real 0m0.008s 
user 0m0.000s 
sys  0m0.004s 

[email protected]:~/dev/stackoverflow$ time ./ccat <w> ww 
real 0m0.060s 
user 0m0.056s 
sys  0m0.000s 

[email protected]:~/dev/stackoverflow$ time ./ccat 0x100000 <w> ww 
real 0m0.060s 
user 0m0.058s 
sys  0m0.000s 

[email protected]:~/dev/stackoverflow$ time ./ccat 0 <w> ww 
real 0m5.326s 
user 0m0.632s 
sys  0m4.684s 

[email protected]:~/dev/stackoverflow$ time ./ccat -0x1000 <w> ww 
real 0m0.533s 
user 0m0.104s 
sys  0m0.428s 

正如你可以看到:

  • 设置stdinstdout非缓冲导致程序变慢几乎相差,
  • 使用行缓冲减慢了因子(因为线短,9〜10字节平均)使用较大的缓冲液没有表现出任何改善
  • ,定时差不显著,
  • 幼稚实现是相当快的,但真正cat实用程序使用执行时间更快,速度更快的API。

这样的结论:没有设置stdinstdout非缓冲,它会为中等甚至大型文件显著影响性能。

相关问题