聊聊文件I/O

对于开发者开说,I/O是绕不过的话题。从文件I/O到网络I/O,存在着各种各样的概念和模型,今天来聊聊文件I/O。

类型对应API
缓冲I/Ofopen,fclose,fseek,fflush,fead,fwrite,fprintf,fscanf……
直接I/Oopen,close,lseek,fsync,read,write,pread,pwrite……

在讲文件I/O之前先弄清楚几个概念:
应用程序内存: 是通常写代码用malloc/free、new/delete登分配出来的内存。
用户缓冲区: C语言中的FILE结构体里面的buffer。FILE结构体的定义如下,可以看到里面有定义的buffer;

typedef strust
{
	short level;
	short token;
	short bsize;
	char fd;
	unsigned flags;
	unsigned char hoid;
	unsigned char *buffer;
	unsigned char &curp;
	unsigned istemp;	
}FILE;

内核缓冲区: Linux操作系统的page cache 。为了加快磁盘的I/O,Linux系统会把磁盘上的数据以page为单位缓存在操作系统的内存里,这里的page是Linux系统定义的一个逻辑概念,一个page一般是4K。

对于缓存I/O,一个读操作会有3次数据拷贝,一个写操作也有3次数据拷贝。
读:磁盘–>内核缓冲区–>用户缓冲区–>应用程序内存;
写:应用程序内存–>用户缓冲区–>内核缓冲区–>磁盘。

对于直接I/O,一个读操作会有2次数据拷贝,一个写操作,也有2次数据拷贝;
读:磁盘–>内核缓冲区–>应用程序内存;
写:应用程序内存–>内核缓冲区–>磁盘。

内存映射文件
相比于直接I/O,内存映射文件往前更进了一步。当用户空间不再用物理内存,直接拿应用程序的逻辑内存地址映射到Linux操作系统的内核缓冲区,应用程序虽然读写的是自己的内存,但这个内存只是一个“逻辑地址”,实际读写的是内核缓冲区。
数据拷贝次数从缓冲I/O的3次,到直接I/O的2次,再到内存映射文件,变成1次。
读:磁盘–>内核缓冲区;
写:内核缓冲区–>磁盘。
在Linux系统中,内存映射文件的的系统API:


    void* mmap(void* start,size_t length,int port,int flags,int fd, off_t orrset);

当用户需要把文件中的数据发送到网络的时候,如果不用零拷贝,实现方式:
实现方式(1):直接I/O 方式,伪代码如下:

	fd1=打开的文件描述符
	fd2=打开的socket描述符
	buffer=应用程序内存
	read(fd1,buffer...); //先把数据从文件中读出来
	write(fd2,buffer...); //再通过网络发出去

如图所示:整个过程会有4次数据拷贝,读2次,写2次;
直接I/O
实现方式(2):内存映射方式,伪代码如下:


    fd1=打开的文件描述符
	fd2=打开的socket描述符
	buffer=应用程序内存
	mmap(fd1,buffer...); //先把磁盘数据映射到buffer上
	write(fd2,buffer...); //再通过网络发出去

如图所示:整个过程有3次数据拷贝,不再经过应用程序内存,直接在内核空间中,从内核缓冲区拷贝到socket缓冲区。
映射文件

零拷贝
零拷贝是提升I/O效率的又一利器,Kafka中在消费消息的时候就是利用了零拷贝技术。
如图所示,零拷贝连内核缓冲区到socket缓冲区的拷贝也省了。内核缓冲区和socket缓冲区没做数据拷贝,只是一个地址的映射,底层的网卡驱动程序要读取数据并发送到网络的时候,看似读的是socket缓冲区的数据,但实际上直接读取是内存缓冲区的数据。在这里,虽然叫零拷贝,实际是有2次数据拷贝,1次是从磁盘到内核缓冲区,1次是从内核缓冲区到socket缓冲区。之所以叫零拷贝,是从内存的角度来看的,数据在内存中没有发生数据拷贝,只在内存和I/O之间传输。
零拷贝
在Linux系统中,零拷贝的API为:

	sendfile(int out_fd, int in_fd, off_t  *offset, size_t count);

最后总结一下:对于把文件数据发送到网络的这个场景,直接I/O、内存映射文件、零拷贝对应的数据拷贝次数分别是:4次、3次、2次,内存拷贝分别是:2次、1次、0次。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值