下表列出了缓冲I/O和直接I/O的API接口列表,缓冲I/O是C语言提供的库函数,均以f打头;直接I/O是Linux的系统API,也是C语言编写的,但在原理上二者差别很大。缓存
类型 | 对应API接口 |
---|---|
缓冲I/O | fopen,fclose,fseek,fflush,fread,fwrite,fprintf,fscanf... |
直接I/O | open,close,lseek,fsync,read,write,pread,pwrite... |
在阐述两者的原理对比以前,先解释几个关键概念:网络
对于缓冲I/O,每一个读写操做会有3次数据拷贝。例如读:磁盘->内核缓冲区->用户缓冲区->应用程序内存。
对于直接I/O,每一个读写操做会有2次数据拷贝,跳过了用户级的缓冲。多线程
关于缓冲I/O和直接I/O,有几点须要特别说明:并发
用户空间不分配物理内存,直接将应用程序的逻辑内存地址映射到Linux操做系统的内核缓冲区,应用程序读写的时候实际读写的是内核缓冲区。此时数据的拷贝次数减小为了1次。socket
当用户须要把文件中的数据发送到网络的时候,使用直接I/O的话会有4次数据拷贝,读进来2次,写回去2次。使用内存映射文件的话会有3次数据拷贝,再也不通过用户程序内存,直接在内核空间中从内核缓冲区拷贝到socket缓冲区。
但若是使用零拷贝,在内核缓冲区和socket缓冲区之间不会使用数据拷贝,只是一个地址的映射,底层的网卡驱动程序要读取数据并发送到网络的时候,看似读的是socket缓冲区的数据,实际上直接读的是内核缓冲区中的数据。
在Linux系统中,零拷贝的系统API为:函数
#include<sys/sendfile.h> ssize_t senfile(int out_fd, int in_fd, off_t *offset, size_t count);