零拷贝

1.为什么使用零拷贝

我们假设一个场景,将本地文件上传到网络上,伪代码如下:

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

注意,别看代码操作就读和写两个,实际在操作系统中涉及到4次以上的数据复制以及上下文切换,如图

注意:该图分成上下两部分,上面是上下文切换,下面是对应的数据在内存中的操作

过程是这样的:

步骤一:由user context切换到 kernel context,从磁盘读取文件数据,DMA引擎复制改数据到kernel buffer。这里涉及到一次上下文切换和数据复制。

步骤二:由kernel context 切换到user context,数据从kernel buffer 复制到user buffer,这里也涉及到一次上下文切换和cpu数据复制。

步骤三:由user context切换到kernel context,数据从user buffer 经cpu复制到socket buffer,这里涉及到一次上下文切换和数据复制。

步骤四:到达这一步的时候,操作系统会返回操作结果,什么意思呢,就是说你的数据没有传输完成就已经返回了,返回结果只是代表数据已经开始传输,并不意味着传输过程已经结束,所以这个步骤是独立和异步的,该步骤也会切换上下文,由kernel context 到user context,并且由DMA引擎从socket buffer复制数据到protocol buffer。

从上面步骤可以看出,整个过程涉及到了多次上下文切换和数据复制,那么,有没有办法避免在user和kernel buffer之间复制数据呢,答案是有的。

mmap

伪代码如下:

tmp_buf = mmap(file, len);
write(socket, tmp_buf, len);

流程图

从流程图可知,使用mmap上下文切换次数没变,但是共享了kernel buffer,直接从kernel buffer复制数据到 socket buffer,减少了kernel buffer和user buffer的交互。注意使用mmap的时候是有一个陷进的,当一个线程使用mmap进行读写的时候,如果另外一个线程删除了文件,会报错。可以通过file leasing方法进行解决,具体解决过程,这里不进行讲解。

综上,该流程还是涉及到了一次cpu copy。这里我们要弄清一个概念,所谓的零拷贝,指的是kernel buffer和user buffer之间的拷贝次数,所以这里并没有达到零拷贝的效果,继续往下看。

 

sendfile

伪代码如下:

sendfile(socket, file, len);

流程如图

该过程不仅减少了两次上下文切换,而且也只进行了一次cpu copy,且没有陷进。

说了这么多,还是没有实现零拷贝,也就是cpu copy的次数为零。

那么有办法实现吗,答案是肯定的。依赖于网络的聚集操作接口,意思就是不需要连续的内存空间。

如图,socket buffer中存放的是数据的地址描述,而不是数据,聚集操作会根据地址描述找到对应的数据,然后进行复制。

 

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值