当前位置: 首页 > news >正文

零拷贝详解

1、在没有DMA技术之前的I/O过程是这样的:

  • CPU发出对应的指令给磁盘控制器,然后返回
  • 磁盘控制器收到指令后,于是就开始准备数据,会把数据放入到磁盘控制器的内部缓冲区,然后产生中断
  • CPU收到中断信号后,停下手头工作,接着把磁盘控制器的缓冲区的数据一次一个字节地读进自己的寄存器。然后再把寄存器里的数据写入到内存,而在数据传输的期间CPU是无法执行其他任务 的。

在这里插入图片描述

整个传输过程中都要CPU亲自参与搬运数据的过程,而且这个过程,CPU是不能做其他事情的。这会大大降低CPU的效率,并且如果使用千兆网卡或者硬盘传输大量数据时,都用CPU搬运的话,肯定忙不过来

2、DMA技术

直接内存访问 (Direct Memory Access) ,简单理解就是,在进行I/O设备和内存的数据传输的时候,数据搬运的工作全部交给DMA控制器,而CPU不再参与任何与数据搬运相关的事情,这样CPU就可以去处理其他的事务。

在这里插入图片描述

与磁盘的交互(IO操作)都交给了DMA控制器去做,CPU得到解放

具体过程:

  • ⽤户进程调⽤ read ⽅法,向操作系统发出 I/O 请求,请求读取数据到⾃⼰的内存缓冲区中,进程进⼊阻塞状态;
  • 操作系统收到请求后,进⼀步将 I/O 请求发送 DMA ,然后让 CPU 执⾏其他任务;
  • DMA 进⼀步将 I/O 请求发送给磁盘;
  • 磁盘收到 DMA 的 I/O 请求,把数据从磁盘读取到磁盘控制器的缓冲区 中,当磁盘控制器的缓冲区被读满后,向 DMA 发起中断信号,告知⾃⼰缓冲区已满;
  • DMA 收到磁盘的信号,将磁盘控制器缓冲区中的数据拷⻉到内核缓冲区中 ,此时不占⽤ CPU,CPU 可以执⾏其他任务;
  • 当 DMA 读取了⾜够多的数据,就会发送中断信号给 CPU;
  • CPU 收到 DMA 的信号,知道数据已经准备好,于是将数据从内核拷⻉到⽤户空间 ,系统调⽤返回

早期DMA只存在于主板上,如今IO设备越来越多,数据传输的需求也不尽相同,所以每个I/O设备里面都有自己的DMA控制器

3、传统的文件传输

如果服务端要提供文件传输的功能,我们能想到的最简单的方式是:将磁盘上的文件读取出来,然后通过网络协议发送给客户端。

而传统的I/O的工作方式是,数据读取和写入是从用户空间到内核空间来回复制,而内核空间的数据是通过操作系统的I/O接口从磁盘读取或写入。

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

这两行代码干了非常多的事,如图:

在这里插入图片描述

可以看到,这期间发生了4次用户态与内核态的上下文切换 ,因为发生了两次系统调用,一次是read(),一次是write()。每一次系统调用,都要从用户态切换到内核态,等内核态完成任务后又要切换回用户态。而上下文切换的成本也很大,尤其在高并发的场景下,这类时间容易被累积放大,从而影响系统的性能。

其次,还发生了4次数据拷贝 ,两次是DMA拷贝,两次是CPU拷贝。

  • 第⼀次拷⻉,把磁盘上的数据拷⻉到操作系统内核的缓冲区⾥,这个拷⻉的过程是通过 DMA 搬运的。
  • 第⼆次拷⻉,把内核缓冲区的数据拷⻉到⽤户的缓冲区⾥,于是我们应⽤程序就可以使⽤这部分数据了,这个拷⻉到过程是由 CPU 完成的。
  • 第三次拷⻉,把刚才拷⻉到⽤户的缓冲区⾥的数据,再拷⻉到内核的 socket 的缓冲区⾥,这个过程依然还是由 CPU 搬运的。
  • 第四次拷⻉,把内核的 socket 缓冲区⾥的数据,拷⻉到⽹卡的缓冲区⾥,这个过程⼜是由 DMA 搬运的

只是搬运一份数据,结果却进行了四次数据拷贝,过多的数据拷贝会消耗CPU资源,大大降低系统性能。

这种传统的文件传输存在冗余的上下文切换和拷贝次数!

优化文件传输

1、如何减少用户态与内核态的上下文切换的次数

读取磁盘数据时,之所以要发生上下文切换,这是因为用户空间没有权限操作磁盘或网卡,内核的权限最高。所以一般要通过内核去完成某些任务的时候,就需要使用操作系统提供的系统调用函数。

而一次系统调用必然会发生2次上下文切换:从用户态切换到内核态,内核态完成任务后再切换回用户态

所以要减少上下文切换的次数就要减少系统调用的次数

2、如何减少数据拷贝的次数

传统的文件传输过程会经过四次数据拷贝,而这其中,从内核的读缓冲区拷贝到用户的缓冲区中,再从用户的缓冲区拷贝到socket的缓冲区 ,这个过程是没有必要的。因为文件传输的应用场景中,在用户空间我们并不会对数据再加工 ,可以省去拷贝到数据缓冲区这一步。

零拷贝

1、实现零拷贝技术的方式通常有2种:

  • mmap+write
  • sendfile

它们是如何减少上下文切换和数据拷贝的次数?

2、mmap+write

read()系统调用的过程,会将内核缓冲区的数据拷贝到用户的缓冲区,为了减少这一步开销,我们可以用mmap()替换read()系统调用函数。

buf = mmap(file, len);
write(sockfd, buf, len);

mmap()系统调用函数会直接把内核缓冲区里的数据映射到用户空间,这样操作系统内核与用户空间就不需要再进行任何的数据拷贝操作

这样做会将内核的读缓冲区拷贝到用户缓冲区,再从用户缓冲区拷贝到socket的缓冲区 这两次拷贝变成内核缓冲区拷贝到socket缓冲区 这一次拷贝

即从原来的四次拷贝变为三次拷贝,减少了一次数据拷贝的过程。

但这并不是理想的零拷贝,因为仍然需要通过CPU把内核缓冲区的数据拷贝到socket缓冲区中,而且仍然需要4次上下文切换

3、sendfile

在Linux内核版本2.1中,提供了一个专门发送文件的系统调用函数sendfile()。

  • ⾸先,它可以替代前⾯的 read() 和 write() 这两个系统调⽤,这样就可以减少⼀次系统调⽤ ,也就减少了 2 次上下⽂切换的开销。
  • 其次,该系统调⽤,可以直接把内核缓冲区⾥的数据拷⻉到 socket 缓冲区⾥ ,不再拷⻉到⽤户态,这样就只有 2 次上下⽂切换,和 3 次数据拷⻉。

从 Linux 内核 2.4 版本开始起,对于⽀持⽹卡⽀持 SG-DMA 技术的情况下, sendfile() 系统,调⽤的过程发⽣了点变化,具体过程如下:

  • 第⼀步,通过 DMA 将磁盘上的数据拷⻉到内核缓冲区⾥;(DMA拷贝)
  • 第⼆步,缓冲区描述符和数据⻓度传到 socket 缓冲区,这样⽹卡的 SG-DMA 控制器就可以直接将内核缓存中的数据拷⻉到⽹卡的缓冲区⾥ ,此过程不需要将数据从操作系统内核缓冲区拷⻉到socket 缓冲区中,这样就减少了⼀次数据拷⻉;(SG-DMA拷贝)

所以,这个过程之中,只进行了一次系统调用(sendfile(),进⾏了 2 次数据拷⻉(磁盘到内核,内核到网卡)

这就是所谓的零拷贝技术。因为我们没有在内存层面去拷贝数据,全程没有通过CPU来搬运数据

在这里插入图片描述

4、总结

实现零拷贝技术的文件传输方式相比传统文件传输的方式,减少了2次上下文切换和数据拷贝次数。只需要进行两次上下文切换和两次数据拷贝就可以完成文件的传输。并且两次数据拷贝都不要通过CPU完成,是由DMA来完成。总体来看,零拷贝技术可以把文件传输的性能提高至少一倍以上

总结

1、早期I/O操作,内存与磁盘的数据传输的工作都是由CPU完成,此时CPU不能进行其他任务,会特别浪费CPU资源

2、为了解决这一问题,出现了DMA技术。每个I/O设备都有自己的DMA控制器,通过这个DMA 控制器,CPU 只需要告诉 DMA 控制器,我们要传输什么数据,从哪⾥来,到哪⾥去,就可以放⼼离开了。后续的实际数据传输⼯作,都会由 DMA 控制器来完成,CPU 不需要参与数据传输的⼯作。

3、传统的IO工作方式,从硬盘读取数据,通过网卡向外发送 。需要进行4次用户态与内核态之间的上下文切换,4次数据拷贝。其中2次数据拷贝发生在内核的缓冲区和对应的硬件设备(磁盘、网卡)之间,由DMA完成;2次数据拷贝发送在用户态和内核态之间,由CPU完成。这种传输方式有冗余的上下文切换次数和数据拷贝次数!

4、对于文件传输的优化,实现零拷贝。通过一次系统调用(sendfile)合并了磁盘读取(read)和网络发送(write)两个操作 ,降低了上下文切换次数;只进行了两次数据拷贝,从磁盘文件到内核缓冲区,从内核缓冲区到网卡,都是由DMA搬运,降低了数据拷贝次数

5、零拷贝技术是基于 PageCache 的,PageCache 会缓存最近访问的数据,提升了访问缓存数据的性能,同时,为了解决机械硬盘寻址慢的问题,它还协助 I/O 调度算法实现了 IO 合并与预读,这也是顺序读⽐随机读性能好的原因。这些优势,进⼀步提升了零拷⻉的性能。

6、当传输大文件时,不能使用零拷贝,因为可能由于 PageCache 被⼤⽂件占据,⽽导致「热点」小文件无法利用到 PageCache,并且大文件的缓存命中率不⾼,这时就需要使用「异步 IO + 直接 IO 」的方式。

相关文章:

零拷贝详解

1、在没有DMA技术之前的I/O过程是这样的: CPU发出对应的指令给磁盘控制器,然后返回磁盘控制器收到指令后,于是就开始准备数据,会把数据放入到磁盘控制器的内部缓冲区,然后产生中断CPU收到中断信号后,停下手…...

新能源汽车电控系统

新能源汽车电控系统主要分为:三电系统电控系统、高压系统电控系统、低压系统电控系统 三电系统电控系统 包括整车控制器、电池管理系统、驱动电机控制器等。 整车控制器VCU 整车控制器作为电动汽车中央控制单元,是整个控制系统的核心,也是…...

Azure概念介绍

云计算定义 云计算是一种使用网络进行存储和处理数据的计算方式。它通过将数据和应用程序存储在云端服务器上,使用户能够通过互联网访问和使用这些资源,而无需依赖于本地硬件和软件。 发展历史 云计算的概念最早可以追溯到20世纪60年代的时候&#x…...

Zabbix监控MySQL数据库实战

zabbix监控mysql的方式 只是安装agent 启用模板监控 启用自定义脚本的模板监控 使用zabbix模版及结合shell脚本监控mysql 创建mysql的zabbix授权用户 mysql> grant all PRIVILEGES on *.* to zabbixlocalhost identified by zabbix; ###创建一个有权限的访问用户lqb密码设…...

代理模式(Java实现)

代理模式是常见的设计模式之一,顾名思义,代理模式就是代理对象具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理。(为真实对象提供代理,然后供其他对…...

炬芯科技发布全新第二代智能手表芯片,引领腕上新趋势!

2023年7月,炬芯科技宣布全新第二代智能手表芯片正式发布。自2021年底炬芯科技推出第一代的智能手表芯片开始便快速获得了市场广泛认可和品牌客户的普遍好评。随着技术的不断创新和突破,为了更加精准地满足市场多元化的变幻和用户日益增长的体验需求&…...

Linux学习之iptables规则基本演示

cat /etc/redhat-release看到操作系统是CentOS Linux release 7.6.1810,uname -r看到内核版本是3.10.0-957.el7.x86_64,iptables --version可以看到iptables版本是v1.4.21。 iptables的filter表 iptables -t filter 命令 规则链 规则 动作是iptables的…...

探索Python编程的技巧:多线程魔法、网络舞台、正则魔法阵与递归迷宫

一 多线程 1.1 进程和线程 进程: 就是一个程序,运行在系统之上,称这个程序为一个运行进程,并分配进程ID方便系统管理。线程:线程是归属于进程的,一个进程可以开启多个线程,执行不同的工作&…...

uniapp-微信小程序篇

uniapp-微信小程序篇 一、创建项目(以Vue3TS 项目为示例) 可以通过命令行的方式创建也可以通过HBuilderX进行创建(通过HBuilderX创建的项目建议选择最简单的模板),个人建议使用命令行方式。 (1) 命令行方式: npx degit dcloudio…...

使用pymupdf实现PDF内容搜索并显示功能

简介: 在日常工作和学习中,我们可能需要查找和提取PDF文件中的特定内容。本文将介绍如何使用Python编程语言和wxPython图形用户界面库来实现一个简单的PDF内容搜索工具。我们将使用PyMuPDF模块来处理PDF文件,并结合wxPython构建一个用户友好的…...

Dalsa线阵相机说明(Linea Color GigESeries 2k and 4K)

文章目录 一. Dalsa相机软件整体架构二. 相机编号说明以及软件要求三. 相机硬件参数三. 相机基本参数四. 软件参数设置列表1. Sensor Control Category2. I/O Control Category3. Counter and Timer Control Category4. Advanced Processing Control Category(1) 平场校正介绍(…...

图神经网络 day2 图的分类

图神经网络基础算法 1 GCN2 GraphSAGE2.1 采样:采样固定长度的邻居2.2 聚合2.3 GraphSAGE_minibatch2.4 GraphSAGE_embedding 3 GAT4. 图网络的分类4.1 递归图神经网络 RGNN4.2 图卷积神经网络GCN4.3 图注意力网络 GAT4.4 图自动编码 GAE4.5 图时空网络 GSTN4.6 图生…...

CentOS防火墙操作:开启端口、开启、关闭、配置

一、基本使用 启动: systemctl start firewalld 关闭: systemctl stop firewalld 查看状态: systemctl status firewalld 开机禁用 : systemctl disable firewalld 开机启用 : systemctl enable firewalld systemctl是…...

Chromium 如何在c++里面控制扩展加载

扩展安装 主要是通过UserMayLoad 函数控制,true允许加载,否则禁用 引自chromiun参考。【一般可以根据扩展ID禁用】 chrome\browser\extensions\standard_management_policy_provider.cc bool StandardManagementPolicyProvider::UserMayLoad( const Ext…...

分类预测 | MATLAB实现MTBO-CNN多输入分类预测

分类预测 | MATLAB实现MTBO-CNN多输入分类预测 目录 分类预测 | MATLAB实现MTBO-CNN多输入分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.MATLAB实现MTBO-CNN多输入分类预测 2.代码说明:基于登山队优化算法(MTBO)、卷积神经…...

操作符和表达式求值

目录 1.运算符的优先级和结合性 1.1运算符的优先级 1.2结合性 2.操作符的使用最终带来的是一个表达式的值 2.1.隐式类型转换(整型提升) 2.1.1整形提升的例子 2.2算术转换 1.运算符的优先级和结合性 运算符是编程语言中的基本元素之一,主…...

Unity Spine帧事件

SpinePro中添加事件帧 首先 选中右上角的层级树 然后选择事件选项 最后在右下角看到 新建 点击它 新建一个事件 点击左上角的设置按钮 弹出编辑窗口 编辑窗口 在右上角 动画栏 可以切换对应的动画 点坐边的那个小灰点来切换 亮点代表当前动画 选中帧 添加事件 点击对应事件…...

AE使用(一)

打开AE 点击“新建合成” 注意参数:宽度高度是视频是横屏还是竖屏。发布在抖音上,需要做出来竖屏效果;发布在视频网站中需要做出横屏效果。没用特殊需求,默认参数就行。 导入素材:左键双击“导入素材区”的空白部分。 …...

YOLOv5、YOLOv8改进:MobileViT:轻量通用且适合移动端的视觉Transformer

MobileViT: Light-weight, General-purpose, and Mobile-friendly Vision Transformer 论文:https://arxiv.org/abs/2110.02178 1简介 MobileviT是一个用于移动设备的轻量级通用可视化Transformer,据作者介绍,这是第一次基于轻量级CNN网络性…...

06-4_Qt 5.9 C++开发指南_MDI应用程序设计

文章目录 1. MDI简介2. 文档窗口类 QFormDoc 的设计3. MDI主窗口设计与子窗口的使用3.1 主窗口界面设计3.2 MDI子窗口的创建与加入3.3 QMdiArea 常用功能函数3.4 MDI的信号 4. 源码4.1 qwmainwindow.h4.2 qwmainwindow.cpp 1. MDI简介 传统的应用程序设计中有多文档界面(Multi…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题

分区配置 (ptab.json) img 属性介绍&#xff1a; img 属性指定分区存放的 image 名称&#xff0c;指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件&#xff0c;则以 proj_name:binary_name 格式指定文件名&#xff0c; proj_name 为工程 名&…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...