0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

传统IO演化至零拷贝的过程

科技绿洲 来源:Linux开发架构之路 作者:Linux开发架构之路 2023-11-09 09:09 次阅读

零拷贝(Zero-Copy)用于在数据读写过程中减少不需要的CPU拷贝,CPU就那么几个,减少它的负担自然可以提高处理效率。数据传输有本地的文件拷贝和通过socket进行文件传输两种,两者区别不大,只是文件数据最终的去向仍然是本地磁盘还是网卡的区别,这里以socket文件为例介绍传统IO演化至零拷贝的过程。

介绍零拷贝之前,可以先看一下传统IO,借此熟悉一些相关概念,先上图:

图片

首先要知道操作系统已经隔离了两块运行空间,即用户空间和内核空间。可以理解为用户程序是跑在用户空间的,而操作系统的内核代码是跑在内核空间的,把这两个隔离是为了用户程序的故障不影响操作系统。其实现代操作系统已经对数据的拷贝做了优化,之前把数据从底层硬件拷贝到内核空间也是CPU来的,现在CPU只需要通知一下DMA(Direct Memory Access,直接内存存取),拷贝工作就交给DMA了,这样CPU就解放出来做其他事去了,所以现代操作系统底层硬件和内核空间之间的数据拷贝CPU参与的很少可以不予考虑,都是DMA来的,但是内核空间和用户空间之间的活都是CPU亲自上的。

从上图可以看出,传统IO是这么几个步骤:

1.线程在用户空间发起read()读文件,线程从用户态切换为内核态

2.DMA将磁盘数据拷贝到内核缓存后,CPU又将数据从内核缓存拷贝至用户缓存,这时线程又从内核态切换为用户态

3.这时候知道了数据应该往哪里写,CPU将数据从用户缓存拷贝至socket缓存,线程又从用户态切换到内核态

4.最后DMA将数据从内核缓存拷贝到网卡,read()调用结束返回,线程又从内核态切换到用户态

整个过程线程上下文切换了四次,一共有四次拷贝,2次CPU来的,2次DMA来的。观察图不经会想,为啥数据要在用户空间走一趟呢,能不能在内核空间直接从内核缓存到socket缓存呢,答案是可以的,这就是第一种零拷贝技术的原理,即mmap+write,先上图:

图片

mmap即内存映射,mmap()是由unix/linux操作系统来调用的,它可以将内核缓存中的一块区域与用户缓存中的一块区域形成映射关系,即共享内存,不过在用户缓存中的这块映射区域是堆外内存。建立映射关系后,理解起来就是往其中任意一头写另外一头也写进去了,这样是为了省掉一次CPU拷贝,传统IO要把数据从内核缓存拷贝到用户缓存才能写,现在直接在用户缓存写,有了映射关系,对应的那块内核缓存也有了。mmap+write实现的零拷贝流程是这样的:

1.用户进程要读一个磁盘文件,告诉内核进程发起mmap()函数调用,来来来把你的内核缓存和我的一块用户缓存建立下映射关系,我要读这个磁盘文件了。

2.内核进程乖乖调用了mmap()函数,将一块内核缓存和用户缓存中的一块堆外内存建立的映射关系。并且告诉DMA将这个文件中的数据拷贝到了这块内核缓存中。到这里mmap()函数就调用结束了,任务完成。严格的说到这里为止都不算IO过程,因此也没有统计线程的上下文切换次数。

3.这才开始IO,因为磁盘文件已经被DMA拷贝到内核缓存中去了,又被映射到了这块堆外内存,所以就直接在用户缓存里就读到了,线程没有上下文切换,然后准备写进一块socket缓存里去了,线程发起了write()调用,状态由用户态切换为内核态,这时候内核基于CPU拷贝将数据从那块映射着的内核缓存拷贝到socket缓存,CPU也就拷贝了这一次。

4.然后又是DMA将数据从socket缓存拷贝到网卡,最后write()函数调用返回,线程从内核态切换到用户态。

整个过程线程切换了两次,一共有三次拷贝,其中2次DMA拷贝,1次CPU拷贝。到这里CPU已经轻松不少了,就拷贝了一次嘛,可以不是说好的零拷贝的嘛,怎么还有一次拷贝,然后sendfile()函数就登场了,它是实实在在的实现了零拷贝,先上图:

图片

sendfile()也是操作系统来调用的,用户线程只能通过特定的方法发起调用,比如java.nio包下的FileChannel,它的transferTo()方法可以发起sendfile()函数的调用。sendfile()函数实现零拷贝的过程是这样的:

1.用户线程发起sendfile()函数调用,与mmap()函数不同的是,不单单告诉内核去哪里读数据,往哪里写数据也一起告诉内核了。这时候就已经开始算IO了,线程从用户态切换到了内核态。

2.知道了从哪里读数据,依然是DMA去磁盘里把数据拷贝到内核缓存中去,由于同时也知道了应该往哪里写数据,那就接着干活呗。

3.先把数据描述信息从内核缓存复制到指定的socket缓存,然后DMA又来了,这个时候socket缓存中的数据描述信息就起作用了,这些描述信息主要是数据的位置信息等。DMA Gather通过这些数据描述信息将数据从内核缓存拷贝到网卡。

4.sendfile()函数调用结束,线程从内核态切换到了用户态,CPU一次拷贝都没有!零!

这就是真正的零拷贝,整个过程用户线程切换了两次,只有两次拷贝,但都是DMA来的。

关于第三种零拷贝方式,这是Linux2.4对sendfile做了改进之后的零拷贝。其实linux 2.1 内核开始就引入了sendfile()函数,当时的零拷贝是这样的。

图片

可以看出整个过程用户线程切换了两次,有三次拷贝,两次DMA来的,还是有一次CPU拷贝。这种零拷贝方式和mmap+write方式有点类似,但是这也算零拷贝演进过程中的一环。

sendfile()函数的man page里面有这句话: In Linux kernels before 2.6.33, out_fd must refer to a socket. Since Linux 2.6.33 it can be any file. 也就是说Linux2.6.33之前sendfile()只能用于文件到socket的传输。而Linux2.6.33之后可以用于两个文件描述符之间和文件到socket之间的传输。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • IO
    IO
    +关注

    关注

    0

    文章

    435

    浏览量

    39075
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10824

    浏览量

    211097
  • 数据
    +关注

    关注

    8

    文章

    6870

    浏览量

    88800
收藏 人收藏

    评论

    相关推荐

    深度解析Linux中拷贝原理

    所谓「拷贝」描述的是计算机操作系统当中,CPU不执行将数据从一个内存区域,拷贝到另外一个内存区域的任务。通过网络传输文件时,这样通常可以节省 CPU 周期和内存带宽。
    发表于 03-01 14:39 2611次阅读

    利用PLD实现智能演化计算

    演化计算是一种通过模拟的自然界的生物演化过程搜索最优解的方法,主要包括遗传算法(CA)、演化策略(ES)、演化规划(EP)等。演化计算具有子
    发表于 06-26 17:43 24次下载

    RAID中拷贝技术研究

    从实际测试和理论分析角度出发,研究了采用拷贝技术对提高RAID性能的重要性.研究结果表明拷贝技术对RAID性能有很大影响,尤其是在嵌入式环境下,必须采用
    发表于 07-01 17:09 20次下载

    基础学习LEBVIEW】06 IO接口

    基础学习LEBVIEW】06 IO接口,感兴趣的朋友一定要学习。
    发表于 12-31 10:28 0次下载

    用于时钟的动态演化模型及算法

    传统分布仿真系统时钟不一致影响因素分析方法,已不能满足当前面向服务分布仿真的时钟状态分析需要。从系统全局时钟演化出发,阐述了时钟状态演化内涵与过程;在此基础上,基于有限自动机理论,提出
    发表于 11-22 10:34 9次下载
    用于时钟的动态<b class='flag-5'>演化</b>模型及算法

    基于微博文本的词对主题演化模型

    针对传统主题模型忽略了微博短文本和文本动态演化的问题,提出了基于微博文本的词对主题演化( BToT)模型,并根据所提模型对数据集进行主题演化分析。BToT模型在文本生成
    发表于 12-03 11:31 14次下载
    基于微博文本的词对主题<b class='flag-5'>演化</b>模型

    Python如何防止数据被修改Python中的深拷贝与浅拷贝的问题说明

    在平时工作中,经常涉及到数据的传递。在数据传递使用过程中,可能会发生数据被修改的问题。为了防止数据被修改,就需要再传递一个副本,即使副本被修改,也不会影响原数据的使用。为了生成这个副本,就产生了拷贝——今天就说一下Python中的深拷贝
    的头像 发表于 03-30 09:54 3033次阅读
    Python如何防止数据被修改Python中的深<b class='flag-5'>拷贝</b>与浅<b class='flag-5'>拷贝</b>的问题说明

    相场模拟—尽“显”增材制造过程中的晶粒演化

    (powder-bed-fusion, PBF)技术是最常用的AM技术之一。理解并预测PBF过程中晶粒演化对通过调整工艺以定制样件的晶粒结构具有重要的指导意义。 目前,通过数值模拟方法(如元胞自动机法、相场法)可以很好地模拟PBF过程
    的头像 发表于 06-15 15:06 1943次阅读

    深入理解Linux系统拷贝技术

    内存拷贝是比较耗时操作,拷贝是常用优化手段,今天分享的文章就是Linux系统拷贝技术,Kafka和MySQL开源组件都用到这个核心技术,
    的头像 发表于 09-01 15:12 3025次阅读

    详解Linux系统中的拷贝技术

    Linux系统中一切皆文件,仔细想一下Linux系统的很多活动无外乎读操作和写操作,拷贝就是为了提高读写性能而出现的。
    的头像 发表于 05-18 09:18 2336次阅读
    详解Linux系统中的<b class='flag-5'>零</b><b class='flag-5'>拷贝</b>技术

    C++深拷贝和浅拷贝详解

    当类的函数成员存在指针成员时会产生深拷贝和浅拷贝和问题。
    发表于 08-21 15:05 319次阅读
    C++深<b class='flag-5'>拷贝</b>和浅<b class='flag-5'>拷贝</b>详解

    信号驱动IO与异步IO的区别

    , 是开始处理IO, 这个时候还是存在阻塞的,将数据从内核态拷贝进入到用户态的过程至少是阻塞住的 (应用程序将数据从内核态拷贝到用户态的过程
    的头像 发表于 11-08 15:32 993次阅读
    信号驱动<b class='flag-5'>IO</b>与异步<b class='flag-5'>IO</b>的区别

    什么是拷贝技术

    传统操作系统的数据传输过程中,系统内部会在磁盘、内存、缓存中多次进行数据拷贝,每次都会占用CPU的资源,数据量小的时候还好。 随着数据量的增加,CPU的开销也会持续增加,尤其是在机器人图像数据
    的头像 发表于 11-27 16:20 433次阅读
    什么是<b class='flag-5'>零</b><b class='flag-5'>拷贝</b>技术

    如何进行拷贝性能测试

    TogetherROS™·Bot拷贝性能测试 我们使用TogetherROS™·Bot系统内部集成的性能测试工具——performance_test,来评估下开启拷贝前后的性能差异
    的头像 发表于 11-27 16:51 405次阅读
    如何进行<b class='flag-5'>零</b><b class='flag-5'>拷贝</b>性能测试

    磁盘拷贝机会拷贝删除的内容吗

    升级等方面非常有用。 然而,关于磁盘拷贝机是否会拷贝已删除的内容,这取决于拷贝过程中使用的具体方法和工具。以下是对这个问题的分析: 磁盘空间的分配与管理 在深入了解磁盘
    的头像 发表于 10-14 15:38 253次阅读