Friday, July 16, 2010

IO笔记2

两层buffer的存在

 23 #include <stdio.h>
 24
 25 int main(int argc, char *argv[]){
 26     int retval ;
 27     while(1){
 28         char c[BUFSIZ];
 29         retval = read(0, c, 1);
 30         printf("%c\n", *c);
 31     }
 32     return 0;
 33 }

上面的代码, 用户输入一次, read函数被调用N次(数据的长度)。也就是说用户输入的数据已经被缓存了。
再如下:

 23 #include <stdio.h>
 24
 25 int main(int argc, char *argv[]){
 26     int retval ;
 27     int i;
 28     int c;
 29     printf("%d\n", BUFSIZ);
 30     for(i = 0; i < BUFSIZ / 2; i++){
 31         c = fgetc(stdin);
 32     }
 33     return 0;
 34 }

上面的代码fgetc被调用N次(数据的长度), 但是read的调用情况如下:
1. 当stdin不是terminate device时, 被调用一次, read的count参数为4096
2. 当stdin是terminate device时, 被调用两次, read的count参数为1024
* 至少怎么得到这种数据, 答案是使用strace凶器。

libc会根据stdin是什么使用setvbuf对FILE对象设置buffer.

从上面两个例子可以知道:
1. 使用standard I/O从terminate device读数据时, 其实经过了两个buffer机制。
2. standard I/O读不同file descriptor时的buffer大小会变化。 加上从APUE中知道的,情况会是这样
 * 当stdin, stdout是terminate device时, standard I/O会使用行缓存, buffer大小为1024.
 * 当stdin, stdout不是terminate device时, standard I/O会使用full buffer, buffer大小为4096.

好, 知道这两种buffer机制与buffer大小了, 移步看这一篇文章会有很好的收获:
 * http://www.pixelbeat.org/programming/stdio_buffering/

这文章从一个例子开始, 如下:
# tail -f access.log | cut -d' '|uniq
为什么上面的命令没有输出? 呵呵, 其中就是IO缓存的机制.

预读数据, 减少read, write

使用standard I/O都是会预读一定数量的数据, 用于减少调用read, write的次数.
使用standard I/O的好处就是程序员无需操心这个预读数据的大小, 只需要知道它是预读的即可.
如果不知道会预读的话, 上面的URL的例子就无法明白.


No comments:

Post a Comment

Note: Only a member of this blog may post a comment.