一、来看一个例子

  • 下面的程序从标准输入获取数据,然后将内容输出到标准输出中:
#include <stdio.h>
#include <unistd.h>

#define BUFFSIZE 4096

int main()
{
int n;
char buf[BUFFSIZE];

while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if(write(STDOUT_FILENO, buf, n) != n)
perror("write error");

if(n > 0)
perror("read error");

return 0;
}
  • 运行效果如下: 

APUE编程:13---文件I/O之(I/O的效率)_标准输入

  • 程序说明:

  • 它从标准输入读、写到标准输出,这就界定它执行本程序之前,这些标准输入、输出已由shelle安排好。确实,所有常用的UNIX系统shell都提供了一种方法,它在标准输入上打开一个文件用于读,在标准输出创建(或重写)一个文件。这使得程序不必打开输入和输出文件,并允许用户利用shell的I/O重定向功能
  • 考虑到进程终止时,UNIX系统内核会关闭进程的所有打开的文件描述符,因此本程序并不关闭输入和输出文件
  • 对UNIX系统内核而言,文本文件和二进制代码文件并无区别,所以本程序对这两种文件都有效

二、缓冲区的取值分析


  • 上面的程序read()和write()用到的缓冲区大小由定义的BUFFSIZE常量决定
  • 下面显示了用20种不同的缓冲区长度,读516581760字节的文件所得到的的结果

APUE编程:13---文件I/O之(I/O的效率)_I/O的效率_02

  • 测试环境:我们运行上面的程序,其标准输出被重定向到/dev/null上,测试的文件系统为ext4文件系统,磁盘块长度为4096字节(磁盘块长度由st_blksize表示。这也证明了上图中系统CPU时间的几个最小值差不多出现在BUFFSIZE为4096及以后的位置,继续增加缓冲区的长度对此时间几乎没有影响

三、预读技术


  • 大多数文件系统为改善性能都采用某种预读(read ahead)技术。当检测到正进行顺序读取时,系统就试图读入比应用程序要求的更多数据,并假想应用很快就会读这些数据
  • 预读的结果可以从上图看出,缓冲区长度小至32字节的时钟时间比拥有较大缓冲区长度时的时钟时间几乎一样

四、总结

  • 在其他文件中我们还会回到这一例子当中,其中:

  • “说明同步写的效果”一文中引用到本文
  • “比较不带缓冲的I/O时间与标准I/O库所用的时间”一文中引用到本文

APUE编程:13---文件I/O之(I/O的效率)_unix_03