上架学姐 8 张图,就可以搞懂「零拷贝」了,原来( 二 )

文章图片
首先 , 期间共发生了4次用户态与内核态的上下文切换 , 因为发生了两次系统调用 , 一次是read , 一次是write , 每次系统调用都得先从用户态切换到内核态 , 等内核完成任务后 , 再从内核态切换回用户态 。
上下文切换到成本并不小 , 一次切换需要耗时几十纳秒到几微秒 , 虽然时间看上去很短 , 但是在高并发的场景下 , 这类时间容易被累积和放大 , 从而影响系统的性能 。
其次 , 还发生了4次数据拷贝 , 其中两次是DMA的拷贝 , 另外两次则是通过CPU拷贝的 , 下面说一下这个过程:
第一次拷贝 , 把磁盘上的数据拷贝到操作系统内核的缓冲区里 , 这个拷贝的过程是通过DMA搬运的 。
第二次拷贝 , 把内核缓冲区的数据拷贝到用户的缓冲区里 , 于是我们应用程序就可以使用这部分数据了 , 这个拷贝到过程是由CPU完成的 。
第三次拷贝 , 把刚才拷贝到用户的缓冲区里的数据 , 再拷贝到内核的socket的缓冲区里 , 这个过程依然还是由CPU搬运的 。
第四次拷贝 , 把内核的socket缓冲区里的数据 , 拷贝到网卡的缓冲区里 , 这个过程又是由DMA搬运的 。
我们回过头看这个文件传输的过程 , 我们只是搬运一份数据 , 结果却搬运了4次 , 过多的数据拷贝无疑会消耗CPU资源 , 大大降低了系统性能 。
这种简单又传统的文件传输方式 , 存在冗余的上文切换和数据拷贝 , 在高并发系统里是非常糟糕的 , 多了很多不必要的开销 , 会严重影响系统性能 。
所以 , 要想提高文件传输的性能 , 就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数 。
先来看看 , 如何减少「用户态与内核态的上下文切换」的次数呢?
读取磁盘数据的时候 , 之所以要发生上下文切换 , 这是因为用户空间没有权限操作磁盘或网卡 , 内核的权限最高 , 这些操作设备的过程都需要交由操作系统内核来完成 , 所以一般要通过内核去完成某些任务的时候 , 就需要使用操作系统提供的系统调用函数 。
而一次系统调用必然会发生2次上下文切换:首先从用户态切换到内核态 , 当内核执行完任务后 , 再切换回用户态交由进程代码执行 。
所以 , 要想减少上下文切换到次数 , 就要减少系统调用的次数 。
再来看看 , 如何减少「数据拷贝」的次数?
在前面我们知道了 , 传统的文件传输方式会历经4次数据拷贝 , 而且这里面 , 「从内核的读缓冲区拷贝到用户的缓冲区里 , 再从用户的缓冲区里拷贝到socket的缓冲区里」 , 这个过程是没有必要的 。
因为文件传输的应用场景中 , 在用户空间我们并不会对数据「再加工」 , 所以数据实际上可以不用搬运到用户空间 , 因此用户的缓冲区是没有必要存在的 。
零拷贝技术实现的方式通常有2种:
mmap+write
sendfile
下面就谈一谈 , 它们是如何减少「上下文切换」和「数据拷贝」的次数 。
在前面我们知道 , read系统调用的过程中会把内核缓冲区的数据拷贝到用户的缓冲区里 , 于是为了减少这一步开销 , 我们可以用mmap替换read系统调用函数 。
buf=mmap(file,len);write(sockfd,buf,len);
mmap系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间 , 这样 , 操作系统内核与用户空间就不需要再进行任何的数据拷贝操作 。

文章图片
具体过程如下:
应用进程调用了mmap后 , DMA会把磁盘的数据拷贝到内核的缓冲区里 。 接着 , 应用进程跟操作系统内核「共享」这个缓冲区;
应用进程再调用write , 操作系统直接将内核缓冲区的数据拷贝到socket缓冲区中 , 这一切都发生在内核态 , 由CPU来搬运数据;
推荐阅读
- 华为|支持5G!曝华为Mate 40E Pro将于3月3日上架:搭载麒麟9000L
- NVIDIA|RTX 3060 Ti悄然变"心":索泰上架三款GA103核心新版本
- Intel|Intel全新阿特拉斯峡谷NUC迷你机上架:10nm 10W奔腾、2999元
- 爱奇艺|爱奇艺奇遇Dream VR一体机上架:2699元 一年内打卡300天0元购
- 显示器|首发12999元!外星人34英寸量子点带鱼屏显示器上架:4K/175Hz
- 华为|4599元到手!华为新款MateBook D15锐龙版上架:搭载R5 5500U
- 太阳|有史以来在单张图像中观测到的最大日珥喷发:没有指向地球!
- 天猫|天猫上架100万只冰墩墩全部售罄:你抢到几个
- 天猫|最后实现“一户一墩”的机会来了!天猫今天上架100万只冰墩墩
- 蓝牙耳机|小米有品上架高颜值真无线耳机:40dB主动降噪 地铁变卧室
