前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Operating System 11 - 零拷贝

Operating System 11 - 零拷贝

作者头像
Reck Zhang
发布2021-08-11 11:43:52
2330
发布2021-08-11 11:43:52
举报
文章被收录于专栏:Reck Zhang

零拷贝

legacy

当我们将服务端主机磁盘中的文件不做修改的从已连接的socket发送出的, 通常是这么做的:

代码语言:javascript
复制
while(ret = read(disk_fd, buf, BUF_SIZE) > 0) {
    write(sock_fd, buf, ret);
}

也就是说我们将磁盘中的信息读入到内存中, 再将内存中的信息发送到socket. 但是由于Linux的I/O操作是基于缓冲的. 也是就是说在以上的I/O中, 发生了多次的数据拷贝.

send_file_legacy
send_file_legacy

当应用程序访问某块数据的时候, 会首先检测最近是否有过访问, 文件内容是否在内核中存在缓存. 如果是, 操作系统则直接根据read系统调用提供的buffer地址, 将buffer所指定的数据拷贝到用户态的空间中. 如果不是, 操作系统则首先将磁盘上的数据拷贝到内核态的空间中, 主要是基于DMA, 也就是说这一步是不占用CPU. 然后将数据从内核空间拷贝到用户空间.

接下来, write系统调用再把数据拷贝到内核的网络发送缓冲区中, 直到内容通过网卡发送到网络中完成整个过程, 这以过程也是基于DMA.

那么这个过程中总共发生了4次数据拷贝, 2次是外部设备和中心部件的拷贝, 2次是用户态和内核态的拷贝. 即使是使用DMA来处理与外部设备的通讯, CPU仍然需要进行两次拷贝, 这一过程也发生了用户态和内核态之间的上下文切换, 加重了CPU的负担.

零拷贝

零拷贝的主要任务就是避免CPU将数据从一块存储拷贝到另外一块存储, 从而让CPU解放出来处理其他任务.

sendfile()

代码语言:javascript
复制
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);

系统调用sendfile()表示在in_fd和out_fd之间传输文件内容. out_fd必须指向一个套接字, in_fd指向的必须是可以mmap的. 这也表示了sendfile只能是从文件到套接字.

事实上, 当数据从外存到内核空间后, 我们是将这块缓冲区的描述符和数据长度传给socket缓冲区. 这个过程中只有DMA来完成数据拷贝, CPU并不负责, 并且避免了用户态和内核态之间的切换.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 零拷贝
    • legacy
      • 零拷贝
        • sendfile()
        相关产品与服务
        云硬盘
        云硬盘(Cloud Block Storage,CBS)为您提供用于 CVM 的持久性数据块级存储服务。云硬盘中的数据自动地在可用区内以多副本冗余方式存储,避免数据的单点故障风险,提供高达99.9999999%的数据可靠性。同时提供多种类型及规格,满足稳定低延迟的存储性能要求。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档