经常听到缓冲区的概念,但始终对它的作用与具体实现有很多疑问,最近拜读了《Linux程序设计》 4TH之后,总算有了大概的理解。 该书举了一个例子,对一个10M文件的复制操作三种不同的实现,速度有不同的体现。 首先包含头文件:
|
|
首先看第一个实现,直接使用read与write的系统底层调用进行文件复制:
|
|
以上程序运行之后会将file.in文件复制到file.out文件当中,我们使用TIMEFORMAT="" time ./Test
1.19user 39.37system 0:41.63elapsed 97%CPU (0avgtext+0avgdata 1172maxresident)k 0inputs+24984outputs (0major+63minor)pagefaults 0swaps
也就是我们花了39.37秒才完成了文件复制操作。 我们每次读入1个字节调用一次read函数,10M=1024KB=1048576byte,也就是我们调用了10万次read函数。
我们看下第二个实现,这个实现采用了一个1K的缓冲区:
|
|
0.00user 0.07system 0:00.08elapsed 89%CPU (0avgtext+0avgdata 1112maxresident)k 0inputs+24976outputs (0major+62minor)pagefaults 0swaps
第二个实现则仅仅需要1秒不到的时间即可实现文件复制功能,因为只需要执行1024次操作即可。
下面第三个实现则是使用的标准库里面的文件操作:
|
|
0.40user 0.07system 0:00.52elapsed 92%CPU (0avgtext+0avgdata 1380maxresident)k 0inputs+24976outputs (0major+70minor)pagefaults 0swaps
这种实现所消耗的时间与第二种实现相差不多,但为什么同样是读取一个字符却跟第一个差距这么大,因为在stdio库当中的FILE结构当中实现了一个缓冲区,只有当缓冲区满的时候才会进行调用。
根据上面三个实现,体现了不同的实现效率与性能的极大差异,所以在实际的程序开发当中应该找到性能与稳定的平衡点。