标准 IO 库的缓冲区

来源:互联网 发布:天谕男玉虚捏脸数据图 编辑:程序博客网 时间:2024/06/05 10:18

标准 IO 库的缓冲区

首先需要明确一点: 标准 IO 库提供缓冲区的目的是尽可能减少系统调用 read 和 write 函数的调用次数. 之后会给出例子直观的显示缓冲区的大小对程序性能的影响.

标准 IO 提供了 3 种类型的缓冲:

  1. 全缓冲: 其特点是需要填满缓冲区后才进行实际的 IO 操作(当然, 也可以使用 flush 对缓冲区进行冲洗), 一般对于磁盘上的文件实施的是全缓冲. 默认全缓冲的大小为 4096;
  2. 行缓冲: 当输入输出遇到换行符时, 才执行 IO 操作. 当流涉及一个终端时, 通常使用行缓冲. 行缓冲的长度是固定的, 稍微小一些, 默认是 1024;
  3. 不带缓冲: 标准 IO 库不对字符进行缓冲. 比如标准错误输出 stderr 通常是不带缓冲的, 这样即使没有换行符, 出错信息也能尽快显示. 此时缓冲的大小为 1.

测试缓冲大小对程序性能的影响

下面给出一个例子展示缓冲区的大小对程序性能的影响, 该程序实现对文件的读, 然后将内容显示到屏幕上. 根据上面介绍的内容, 使用标准 IO 库对磁盘上的文件进行处理时, 实施的全缓冲. 之后, 我们将缓冲类型设置为不带缓冲, 从而比较两种类型的缓冲对程序性能的影响.

/* test_buffer.c */#include <stdio.h>#include <stdlib.h>#include <time.h>#include <sys/time.h>#define oops(msg) {perror(msg); exit(1);}int main() {    char buf[100];    FILE *fp;    if ((fp = fopen("file", "r")) == NULL)        oops("fopen");    /*setbuf(fp, NULL);*/    struct timeval t_val, t_val_end, t_result;    gettimeofday(&t_val, NULL);    while (fgets(buf, 100, fp) != NULL)        printf("%s", buf);    gettimeofday(&t_val_end, NULL);    timersub(&t_val_end, &t_val, &t_result);    double consume = t_result.tv_sec + (1.0 * t_result.tv_usec)/1000000;    printf("end.elapsed time= %fs \n", consume);}

其中文件 file 有 20 行, 总共 238 个字符.

  • 当执行上述代码后(注意此时 setbuf(fp, NULL); 被注释了), 结果为:
end.elapsed time= 0.000092s
  • 当将 setbuf(fp, NULL); 的注释去掉, 此时 fp 对应的流是不带缓冲的, 代码的执行结果为:
end.elapsed time= 0.000265s

结果在我们的意料之中. 此时由于关闭缓冲后, 系统调用频繁, 所消耗的时间无疑会增多.

显示缓冲的类型以及大小

下面的例子展示了各个流的缓冲类型以及相应的大小:

/* buffer_info.c */#include <stdio.h>#include <stdlib.h>void pr_stdio(const char*, FILE*);int is_unbuffered(FILE*);int is_linebuffered(FILE*);int buffer_size(FILE*);#define oops(msg) {perror(msg); exit(1);}int main() {    FILE *fp;    pr_stdio("stdin", stdin);    pr_stdio("stdout", stdout);    pr_stdio("stderr", stderr);    if ((fp = fopen("/etc/passwd", "r")) == NULL)        oops("fopen");    if (getc(fp) == EOF)        oops("getc error");    pr_stdio("/etc/passwd", fp);    exit(0);}void pr_stdio(const char *name, FILE *fp) {    printf("stream = %s,  ", name);    if (is_unbuffered(fp))        printf("unbuffered");    else if (is_linebuffered(fp))        printf("line buffered");    else        printf("fully buffered");    printf (", buffer size = %d\n", buffer_size(fp));}int is_unbuffered(FILE *fp) {    return(fp->_flags & _IO_UNBUFFERED);}int is_linebuffered(FILE *fp) {    return(fp->_flags & _IO_LINE_BUF);}int buffer_size(FILE *fp) {    return(fp->_IO_buf_end - fp->_IO_buf_base);}

程序运行的结果为:

stream = stdin,  line buffered, buffer size = 1024                              stream = stdout,  line buffered, buffer size = 1024                             stream = stderr,  unbuffered, buffer size = 1stream = /etc/passwd,  fully buffered, buffer size = 4096
阅读全文
0 0
原创粉丝点击