【IO】IO模型与零拷贝
前言:
正在运行的程序其实就是系统中的一个进程,操作系统会为每一个进程分配内存空间,而内存空间分为两部分,一部分是用户空间,这是用户进程访问的内存区域;另一部分是内核空间,是操作系统内核访问的内存区域。
如网络、磁盘IO等操作,出于安全性考虑,用户进程不能直接与外部设备进行数据交互,用户进程只能向操作系统发起IO调用请求,由操作系统内核与外部设备进行数据交互,完成真正的IO操作。
IO模型:
首先明确一个概念,磁盘、socket通讯的网卡等都属于外部设备。我们经常看到的输入(input)、输出(output)等概念其实就是指用户进程与这些外部设备的交互。
IO实质:
输入(input):将外部设备中的数据加载到用户进程内。
输出(output):将用户进程内的数据迁移到外部设备。
一个完整的IO过程分为几步?
1、用户进程向操作系统发起IO调用请求。
2、操作系统准备数据,将外部设备中的数据加载到内核缓冲区。
3、操作系统拷贝数据,将内核缓冲区的数据拷贝到用户进程缓冲区。
在一次完整IO过程中,根据用户进程的不同表现形式,我们可以将IO模型分成以下几种:
(1)阻塞IO(Blocking IO):

表现:从发起IO调用请求(recvrom系统函数调用)至接收到操作系统内核拷贝来的数据的整个过程中,用户进程一直处于阻塞状态。
(2)非阻塞IO(Non-Blocking IO):

表现:用户进程发起IO调用请求后,如果数据还未准备好,内核会直接返回错误信息,结束用户进程的阻塞状态,用户进程不断轮询发起IO调用请求,直至数据准备就绪。
特点:不像BIO,用户进程在整个IO流程中都是阻塞的,通过轮询发起IO请求来获取数据。相较于BIO有性能提升,但在数据准备好之前,用户进程会不断调用系统函数,占用大量的CPU资源。
(3)IO多路复用:

表现:用户进程调用系统函数select后,可以监控多个fd,只要有任意一个fd的数据准备就绪,select函数就会返回可读提示给用户进程,此时进程再调用recvfrom系统函数读取数据。
特点:解决了NIO频繁的系统调用问题,减少CPU资源的消耗。只有在监视的fd返回可读提升后,用户进程才会调用recvfrom函数,请求获取数据。
fd概念:
1、文件描述符全称File Description,是一个从0开始的无符号整数,每个fd都可以关联一个文件。
2、在linux中,万物皆文件,常规文件、视频、硬件设备、socket等都可以用一个fd来进行关联。
简单提一下,IO多路复用模型涉及到的系统函数有三个:select、poll、epoll。
select函数特点:有连接数限制,一次最多只能监听1024个fd;select函数返回可读提示后,用户进程需要遍历fd集合才能得知哪个fd数据准备就绪(时间复杂度O(n))。
poll函数特点:解决了select函数有连接数限制的问题,但还是需要遍历fd集合。
epoll函数特点:既解决了连接数限制问题,又无需遍历fd集合获取,可以用O(1)的时间复杂度获取可读的fd。
(4)异步(Asynchronous IO):

表现:用户进程发起IO调用请求后,内核直接返回提示信息,在随后的数据准备阶段以及数据拷贝阶段,用户进程不会阻塞;在数据拷贝操作完成后,内核发送信号通知用户进程。
特点:无论是NIO模型还是IO多路复用模型,它们都会在数据拷贝阶段:将数据从内核缓冲区拷贝到用户缓冲区阻塞,而AIO模型实现了真正的IO全过程无阻塞。
零拷贝:
服务端一般都会提供文件下载功能,这个功能的实质是:基于与客户端建立的socket连接,将服务器磁盘上的文件发送到客户端主机的网卡上。
文件下载功能大概的IO流程:
从磁盘中读取数据到应用程序内存:
1、用户进程调用read函数,向操作系统发起IO请求,上下文从用户态切换为内核态。
2、DMA控制器将数据从磁盘控制缓冲区中拷贝到内核缓冲区。
3、CPU再把内核缓冲区的数据,拷贝到用户缓冲区,上下文从内核态切换为用户态,read函数返回。
将应用程序内存中的数据写入到socket:
4、用户进程调用write函数,发起IO调用请求,上下文从用户态切换为内核态。
5、CPU将用户缓冲区中的数据,拷贝到socket缓冲区。
6、DMA控制器再将数据从socket缓冲区,拷贝到网卡设备,上下文从内核态切换回用户态,write函数返回。

如上图所示,整个过程包含4次上下文切换(用户态、内核态转换)、4次数据拷贝操作,效率较低。看到这里,可能大家会对DMA有疑惑,它是什么?有什么用?
DMA:全称Direct Memory Access,直接内存访问,本质上是一块主板上独立的芯片。它的作用是替代CPU完成与IO设备的数据传输工作,减少CPU的负担,提高CPU的利用效率。
读取磁盘文件的完整IO流程:
1、用户进程调用read函数,发起IO调用请求。
2、CPU收到指令后,对DMA控制器发起指令调度。
3、DMA收到IO请求(CPU指令调度)后,请求获取磁盘数据。
4、磁盘将数据放入磁盘控制缓冲区,通知DMA控制器。
5、DMA将数据从磁盘控制缓冲区拷贝到内核缓冲区。
6、DMA通知CPU,CPU负责将数据从内核缓冲区拷贝到用户缓冲区。
7、用户应用进程从内核态切换回用户态。
通过读取磁盘文件的IO流程,我们也不难得到将数据写出到网卡的整个IO流程。
零拷贝概念:不是指没有数据拷贝操作,而是减少上下文切换次数和数据拷贝的次数。
零拷贝实现方案:
(1)mmap&write:使用mmap系统函数代替read系统函数。

流程:DMA将磁盘缓冲区的数据拷贝到内核缓冲区,此时CPU不会将内核缓冲区中的数据拷贝到用户缓冲区,因为内核缓冲区内的数据会被映射到用户空间,但mmap函数返回时,还是会从内核态切换到用户态。
特点:减少了一次数据拷贝操作,但整个IO过程还是有4次上下文切换操作。
(2)sendfile:使用sendfile系统函数代替read、write两个系统函数。

流程:DMA将磁盘缓冲区的数据拷贝到内核缓冲区,随后CPU直接将内核缓冲区内的数据拷贝到socket缓冲区中。
特点:减少了read函数返回时的上下文的切换、write函数调用时的上下文的切换。总计减少了一次数据拷贝操作和两次上下文切换操作。
(3)sendfile&SG-DMA:

流程:DMA将磁盘缓冲区的数据拷贝到内核缓冲区,缓冲区将文件描述符和数据长度传到 socket缓冲区,网卡的SG-DMA控制器可直接将内核缓冲区里的数据拷贝到网卡设备。
特点:整个IO流程不涉及CPU,没有将数据从内核缓冲区拷贝到用户缓冲区这一流程,总计减少了两次数据拷贝操作和两次上下文切换操作。
相关文章:
【IO】IO模型与零拷贝
前言: 正在运行的程序其实就是系统中的一个进程,操作系统会为每一个进程分配内存空间,而内存空间分为两部分,一部分是用户空间,这是用户进程访问的内存区域;另一部分是内核空间,是操作系统内核访…...
鸿蒙 - arkTs:状态管理
状态 State: 在声明式UI中,以状态驱动视图更新 状态(State):指驱动视图更新的数据(被装饰器标记的变量)视图(View):基于UI描述渲染得到的用户界面 使用示例…...
YOLOv5-Lite 树莓派4B 15帧教程
【前言】 由于v5Lite仓库遗漏了不少历史问题,最大的问题是毕业后卷起来了,找不到时间更新。 上面是这篇博客的背景,那么先说下结论,使用 v5lite-e 模型,在 树莓派4B(4G内存) 上,有三…...
2014年第三届数学建模国际赛小美赛A题吹口哨解题全过程文档及程序
2014年第三届数学建模国际赛小美赛 A题 吹口哨 原题再现: 哨子是一种小装置,当空气被迫通过开口时会发出声音。哨声的巨大而引人注目,使其对警察和体育裁判来说至关重要。当救生员、迷路的露营者或犯罪受害者使用它们时,它们可以…...
设计模式-注册模式
设计模式专栏 模式介绍模式特点应用场景注册模式和单例模式的区别代码示例Java实现注册模式Python实现注册模式 注册模式在spring中的应用 模式介绍 注册模式是一种设计模式,也称为注册树或注册器模式。这种模式将类的实例化和创建分离开来,避免在应用程…...
css 美化滚动条样式
ChatgGPT4.0国内站点: 海鲸AI-支持GPT(3.5/4.0),文件分析,AI绘图 在CSS中,你可以使用伪元素::-webkit-scrollbar以及相关的伪元素来为Webkit浏览器(如Chrome和Safari)自定义滚动条的样式。以下是一些基本的CSS规则&am…...
视频压缩不影响画质简单方法,一分钟搞定!
很多朋友在处理视频的时候都会遇到视频过大的问题,想要压缩视频的同时不影响画质,简单的方法有两种。一种是用专业的压缩软件,在压缩的时候设置一个合适的压缩比例,压缩大小的同时保持清晰度,也能提高压缩率࿰…...
Zookeeper的使用场景
统一命名服务 利用ZooKeeper节点的树形分层结构和子节点的顺序维护能力,来为分布式系统中的资源命名。 例:分布式节点命名 分布式消息队列 1.在Zookeeper中创建一个持久节点,用作队列的根节点。队列元素的节点放在这个根节点下。 2.入队:…...
Java 面试题集锦记录
Java 面试题集锦记录 一1. SpringBoot、SpringCloud区别2. SpringCloud怎么保证服务间通信?3. Spring怎么保持高可用性、稳定性?4. 负载均衡5. [Rabbitmq](https://blog.csdn.net/qq_40985985/article/details/128013229) 怎么避免重复消费,[…...
【自然语言处理】第2部分:识别文本中的个人身份信息
自我介绍 做一个简单介绍,酒架年近48 ,有20多年IT工作经历,目前在一家500强做企业架构.因为工作需要,另外也因为兴趣涉猎比较广,为了自己学习建立了三个博客,分别是【全球IT瞭望】,【…...
C#中的.NET与.NET Framework区别
C#是一种编程语言,而.NET是一个开发平台。在.NET生态系统中,有两个相关但不同的概念:.NET和.NET Framework。 .NET Framework 发布时间: .NET Framework是最早引入的,它于2002年首次发布。它是一个用于构建Windows应…...
详解Keras3.0 Layer API: LSTM layer
LSTM layer 用于实现长短时记忆网络,它的主要作用是对序列数据进行建模和预测。 遗忘门(Forget Gate):根据当前输入和上一个时间步的隐藏状态,计算遗忘门的值。遗忘门的作用是控制哪些信息应该被遗忘,哪些…...
Vue和React的运行时,校验引入包的上下文差异
背景 系统使用 webpack 5 模块联邦实现微前端,有关如何实现跨应用的代码共享,可参考 如何优雅的实现跨应用的代码共享 里的第三大点。 总之,这里是其他应用使用了某个应用共享出来的reg文件,引入方式为: import REG …...
C语言中函数调用和嵌套
函数是C语言的基本组成元素 函数调用 根据函数在程序中出现的位置有下列三种函数调用方式: 将函数作为表达式调用 将函数作为表达式调用时,函数的返回值参与表达式的运算,此时要求函数必须有返回值 int retmax(100,150); 将函数作为语句…...
JVM基础篇---02
为什么需要用户自定义类加载器: 扩展类加载器的功能: Java的默认类加载器主要有三个,分别是引导类加载器、扩展类加载器和应用程序类加载器。其中,引导类加载器和扩展类加载器是由JVM实现的,用户无法修改其行为。而应用…...
HTML网站基础
一、前端开发基础 前端一共三门语言——HTML、CSS、JS(Java Script) HTML用于静态网页框架,CSS用于修饰,JS构成动态网页 1、HTML 对于中文网页需要使用 <meta charset"utf-8"> 声明编码,否则会出现…...
最优化考试之惩罚函数外点法
最优化考试之惩罚函数外点法 一、外点法1.问题条件2.解题过程 一、外点法 1.问题条件 目标函数 f ( x ) f(x) f(x)约束函数 g ( x ) g(x) g(x) 2.解题过程 定义罚函数 F ( x ) f ( x ) t ∗ m i n ( 0 , g ( x ) 2 ) F(x)f(x)t*min(0,g(x)^2) F(x)f(x)t∗min(0,g(x)2)对罚…...
JavaScript 数组【详解】
Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍JavaScript中数组详解 数组声明/基础操作以及部分理论知识 🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁 🍉博主收将持续更新学习记录获,友友们有任何问题可…...
Node.js版本对比
目录 1. node版本与Npm版本对照表 2. node版本与node-sass版本对照表 3. node-sass与sass-loader版本对照表 1. node版本与Npm版本对照表 以往的版本 | Node.js 下面显示最新的对应内容,如果需要查找历史版本,可以进入上面的页面查询 VersionLTSDateV8np…...
人工智能:网络犯罪分子的驱动力
随着 2024 年的临近,是时候展望今年的网络安全状况了。由于网络犯罪日益复杂,预计到 2025 年,全球网络安全成本将增至 10.5 万亿美元。 人工智能的使用不断发展,网络犯罪分子变得越来越有创造力 我们注意到,联邦调查…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
云原生安全实战:API网关Envoy的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口,负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...
VSCode 使用CMake 构建 Qt 5 窗口程序
首先,目录结构如下图: 运行效果: cmake -B build cmake --build build 运行: windeployqt.exe F:\testQt5\build\Debug\app.exe main.cpp #include "mainwindow.h"#include <QAppli...
