Netty(IO模型/零拷贝技术/IO复用之select、poll、epoll模型)

news2025/3/14 20:08:50

目录

IO模型

阻塞IO和非阻塞IO

阻塞IO

非阻塞IO

IO复用模型 

异步IO 

mmap

IO复用之select、poll、epoll模型

select 

poll

epoll


IO模型

阻塞IO和非阻塞IO

阻塞IO

所谓阻塞IO就是当应用B发起读取数据申请时,在内核数据没有准备好之前,应用B会一直处于等待数据状态,直到内核把数据准备好了交给应用B才结束。

非阻塞IO

所谓非阻塞IO就是当应用B发起读取数据申请时,如果内核数据没有准备好会即刻告诉应用B,不会让B在这里等待。

术语:非阻塞IO是在应用调用recvfrom读取数据时,如果该缓冲区没有数据的话,就会直接返回一个EWOULDBLOCK错误,不会让应用一直等待中。在没有数据的时候会即刻返回错误标识,那也意味着如果应用要读取数据就需要不断的调用recvfrom请求,直到读取到它数据要的数据为止。

 

IO复用模型 

如果在并发的环境下,可能会N个人向应用B发送消息,这种情况下我们的应用就必须创建多个线程去读取数据,每个线程都会自己调用recvfrom 去读取数据

那么问题来了,这么多的线程不断调用recvfrom 请求数据,先不说服务器能不能扛得住这么多线程,就算扛得住那么很明显这种方式是不是太浪费资源了,线程是我们操作系统的宝贵资源,大量的线程用来去读取数据了,那么就意味着能做其它事情的线程就会少 

所以,有人就提出了一个思路,能不能提供一种方式,可以由一个线程监控多个网络请求,这样就可以只需要一个或几个线程就可以完成数据状态询问的操作,当有数据准备就绪之后再分配对应的线程去读取数据,这么做就可以节省出大量的线程资源出来,这个就是IO复用模型的思路。


IO复用模型的思路就是系统提供了一种函数可以同时监控多个fd的操作,这个函数就是我们常说到的select、poll、epoll函数,有了这个函数后,应用线程通过调用select函数就可以同时监控多个fd,select函数监控的fd中只要有任何一个数据状态准备就绪了,select函数就会返回可读状态,这时询问线程再去通知处理数据的线程,对应线程此时再发起recvfrom请求去读取数据。

异步IO 

到此,还有没有更好的办法,通过观察我们发现,不管是IO复用还是信号驱动,我们要读取一个数据总是要发起两阶段的请求,第一次发送select请求,询问数据状态是否准备好,第二次发送recevform请求读取数据。

 

应用只需要向内核发送一个read 请求,告诉内核它要读取数据后即刻返回;内核收到请求后会建立一个信号联系,当数据准备就绪,内核会主动把数据从内核复制到用户空间,等所有操作都完成之后,内核会发起一个通知告诉应用,我们称这种一劳永逸的模式为异步IO模型。

在IO模型里面如果请求方从发起请求到数据最后完成的这一段过程中都需要自己参与,那么这种我们称为同步请求;反之,如果应用发送完指令后就不再参与过程了,只需要等待最终完成结果的通知,那么这就属于异步。 

mmap

mmap技术,也就是内存映射,可以直接将磁盘文件映射到内核缓冲区。首先还是会发生一次内核态到用户态的切换,这个过程是基于DMA引擎拷贝的,磁盘文件拷贝到内核缓冲区。

接下来,从内核态切换回用户态,此时不会把内核缓冲区的数据拷贝到用户空间。用户缓冲区会跟内核缓冲区建立一个映射,共享一块内存数据,这就不需要从内核缓冲区拷贝到用户缓冲区了。

然后,要把数据通过socket发送出去,需要从用户态切换到内核态,在内核态直接把内核缓冲区的数据拷贝到socket缓冲区里去,然后基于DMA技术把socket缓冲区的数据拷贝到网卡,发送出去。

完成以上步骤之后,就会从内核态切换回用户态。

 

总结来说,需要4次用户态和内核态之间的切换,3次数据的拷贝,比普通的io操纵少了一次数据拷贝,但切换次数并不减少。

IO复用之select、poll、epoll模型

select 

数组

应用进程想要通过select 去监控多个连接(也就是fd)的话需要经向大概如下的流程:

1、在调用select之前告诉select 应用进程需要监控哪些fd可读、可写、异常事件,这些分别都存在一个fd_set数组中。

2、然后应用进程调用select的时候把3个fd_set传给内核(这里也就产生了一次fd_set在用户空间到内核空间的复制),内核收到fd_set后对fd_set进行遍历,然后一个个去扫描对应fd是否满足可读写事件。

 3、如果发现了有对应的fd有读写事件后,内核会把fd_set里没有事件状态的fd句柄清除,然后把有事件的fd返回给应用进程(这里又会把fd_set从内核空间复制用户空间)。

4、最后应用进程收到了select返回的活跃事件类型的fd句柄后,再向对应的fd发起数据读取或者写入数据操作。

通过上面的图我想你已经大概了解了select的工作模式,select 提供一种可以用一个进程监控多个网络连接的方式,但也还遗留了一些问题,这些问题也是后来select面对高并发环境的性能瓶颈。

1、每调用一次select 就需要3个事件类型的fd_set需从用户空间拷贝到内核空间去,返回时select也会把保留了活跃事件的fd_set返回(从内核拷贝到用户空间)。当fd_set数据大的时候,这个过程消耗是很大的。

2、select需要逐个遍历fd_set集合 ,然后去检查对应fd的可读写状态,如果fd_set 数据量多,那么遍历fd_set 就是一个比较耗时的过程。

3、fd_set是个集合类型的数据结构有长度限制,32位系统长度1024,62位系统长度2048,这个就限制了select最多能同时监控1024个连接。

poll

 链表

select模式下 fd_set 长度限制就开始成为了致命的缺陷。

吸取了select的教训,poll模式就不再使用数组的方式来保存自己所监控的fd信息了,poll模型里面通过使用链表的形式来保存自己监控的fd信息,正是这样poll模型里面是没有了连接限制,可以支持高并发的请求。 

和select还有一点不同的是保存在链表里的需要监控的fd信息采用的是pollfd的文件格式,select 调用返回的fd_set是只包含了上次返回的活跃事件的fd_set集合,下一次调用select又需要把这几个fd_set清空,重新添加上自己感兴趣的fd和事件类型,而poll采用的pollfd 保存着对应fd需要监控的事件集合,也保存了一个当返回于激活事件的fd集合。 所以重新发请求时不需要重置感兴趣的事件类型参数。

epoll

红黑树和双链表数据结构,并结合回调机制,造就了epoll的高效。

不同于select 和poll的直接调用方式,epoll采用的是一组方法调用的方式,它的工作流程大致如下:

1、创建内核事件表(epoll_create)。

这里主要是向内核申请创建一个fd的文件描述符作为内核事件表,这个描述符用来保存应用进程需要监控哪些fd和对应类型的事件。
 

2、添加或移出监控的fd和事件类型(epoll_ctl)。

调用此方法可以是向内核的内核事件表 动态的添加和移出fd 和对应事件类型。

 

3、epoll_wait 绑定回调事件

内核向事件表的fd绑定一个回调函数。

当监控的fd活跃时,会调用callback函数把事件加到一个活跃事件队列里;

最后在epoll_wait 返回的时候内核会把活跃事件队列里的fd和事件类型返回给应用进程。

从epoll整体思路上来看,采用事先就在内核创建一个事件监听表,后面只需要往里面添加移出对应事件,因为本身事件表就在内核空间,所以就避免了向select、poll一样每次都要把自己需要监听的事件列表传输过去,然后又传回来,这也就避免了事件信息需要在用户空间和内核空间相互拷贝的问题。

然后epoll并不是像select一样去遍历事件列表,然后逐个轮询的监控fd的事件状态,而是事先就建立了fd与之对应的回调函数,当事件激活后主动回调callback函数,这也就避免了遍历事件列表的这个操作,所以epoll并不会像select和poll一样随着监控的fd变多而效率降低,这种事件机制也是epoll要比select和poll高效的主要原因。
 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/335009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享111个JS菜单导航,总有一款适合您

分享111个JS菜单导航,总有一款适合您 111个JS菜单导航下载链接:https://pan.baidu.com/s/1WkrSIyHC5JySwrCTL0sgLA?pwd13yx 提取码:13yx Python采集代码下载链接:https://wwgn.lanzoul.com/iKGwb0kye3wj base_url "h…

【GPLT 二阶题目集】L2-036 网红点打卡攻略

一个旅游景点,如果被带火了的话,就被称为“网红点”。大家来网红点游玩,俗称“打卡”。在各个网红点打卡的快(省)乐(钱)方法称为“攻略”。你的任务就是从一大堆攻略中,找出那个能在…

开源ChatGPT要来了;软件2.0智能革命;GLM、Diffusion模型大加速

1. 2023年AI十大展望:GPT-4领衔大模型变革,谷歌拉响警报,训练数据告急 新年伊始,大模型的话题热度不减。ChatGPT展现的惊人能力将大模型研究和应用热度推向高潮,人们激烈讨论着这个高级“物种”的推出意味着什么。 本文…

如何操作python的列表和元组?

继上篇文章,我们叙述了 列表是什么? 这篇文章,我们主要叙述 列表如何操作。 如何遍历列表呢?这只需要几行代码,无论列表有多长。 循环让我们能够对列表的每个元素都采取一个或一系列相同的措施, 从而高效地…

CHAPTER 4 Jenkins pipeline (流水线)

Jenkins pipeline4.1 pipeline概念4.2 pipeline优势4.3 pipeline演示1. 新建任务2. 配置任务3. 执行任务4.4 pipeline语法4.4.1 片段生成器1. 生成git clone代码2. 执行任务4.4.2 pipeline语法详解1. 声明式流水线基础2. 脚本化流水线基础3. agent 执行位置4. tool 工具5. envi…

原生微信小程序按需引入vant

vant Vant Weapp - 轻量、可靠的小程序 UI 组件库 1.npm安装 找到项目根目录 安装 # 通过 npm 安装 npm i vant/weapp -S --production# 通过 yarn 安装 yarn add vant/weapp --production# 安装 0.x 版本 npm i vant-weapp -S --production 2 .修改 app.json 将 app.jso…

【GD32F427开发板试用】使用Arm-2D显示电池电量

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:boc 【虽迟但到】 由于快递的原因,11月份申请的,12月1日才收到GD32F427开发板。虽然姗姗来迟,但也没有减少…

易记笔记-Ubuntu升级软件包及注意事项

APT介绍 APT是一个命令行实用程序,用于在Ubuntu系统中安装、删除、更新软件包。 注意,Ubuntu里面的APT工具需要与常说的APT攻击区分开。 APT攻击,即高级可持续威胁攻击,也称为定向威胁攻击,指某组织对特定对象展开的持续有效的攻…

CSDN每日一练:寻因找祖

题目名称&#xff1a;寻因找祖 时间限制&#xff1a;1000ms内存限制&#xff1a;256M 题目描述 寻找因子个数为n的最小整数x. 输入描述&#xff1a; 输入整数n。(1<n<1000) 输出描述&#xff1a; 输出x。 示例 示例1 输入 3 输出 4 提示 无 猛一看&#xff0c;这个题目很…

Node学习1

Node 加载模块&#xff1a; 加载内置模块和第三方模块直接require&#xff08;名字&#xff09; 自定义模块需要加路径 require&#xff08;&#xff09;加载模块时候会自动调用被加载模块代码require永远以module.export所指向的对象为准 模块作用域&#xff1a; 和函数作用…

QT之事件系统

QT之事件系统1. 概述2. 事件的传递3. 事件类型4. 事件处理与事件过滤5. 自定义事件5.1 Demo6. 发送事件7. 参考1. 概述 在QT中&#xff0c;事件均派生自QEvent抽象类&#xff0c;事件可以由任何派生自QObject的子类实例接收和处理。它们与widget关联性极强。 2. 事件的传递 …

有了这 4 款工具,老大再也不怕我写烂SQL了

一、mysqltuner.pl 是 MySQL 一个常用的数据库性能诊断工具&#xff0c;主要检查参数设置的合理性包括日志文件、存储引擎、安全建议及性能分析。针对潜在的问题&#xff0c;给出改进的建议。是 MySQL 优化的好帮手。 在上一版本中&#xff0c;MySQLTuner支持 MySQL / MariaD…

LightningChart JS v4.0.0 and LightningChart NET

LightningChart JS v4.0.0 引入了新的 DataGrid 组件、全面的折线图类型和视觉主题。2023 年 2 月 9 日 - 16:05 新版本特征 下一代色彩主题&#xff1a; 暗金。网络空间。绿松石六角形。光。光自然。自定义 - 创建您自己的下一代颜色主题。新的 DataGrid 组件 DataGrid 组件是…

linux基本功系列之tar命令实战

文章目录前言一. tar命令介绍二. 语法格式及常用选项三. 参考案例3.1 仅打包不压缩3.2 打包后使用调用压缩命令进行压缩3.3 列出文件的内容3.4 追加文件到tar命令中3.5 释放文件到指定的目录四 . 各种压缩方式的比较总结前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓…

开学季该准备哪款电容笔?2023平替电容笔推荐

如今&#xff0c;电容笔越来越受欢迎&#xff0c;性能也越来越好。所以&#xff0c;如何选择一款具有高性价比的电容笔就成了人们的重点关注。现在&#xff0c;越来越多的人开始使用电容笔&#xff0c;所以&#xff0c;人们都在寻求更好、更经济的电容笔。所以&#xff0c;什么…

21省人均GDP超过1万美元,北京以19.01万元继续稳居榜首

在过去的2022年&#xff0c;各省都交了优秀的“成绩单”&#xff0c;各省的经济强弱即将揭晓。广东与江苏的GDP均超过12万亿元&#xff0c;是31省中超过12万亿元的两个城市&#xff0c;GDP分别为12.91万亿元与12&#xff0c;18万亿元。山东省、浙江省、河南省紧随其后&#xff…

linux yum安装卸载jdk8

1>安装1 yum -y list java* 列出jdk列表2 yum install -y java-1.8.0-openjdk-demo.x86_64&#xff08;安装这个java -version 正常显示&#xff0c;但是javac不能用&#xff0c;因为yum install java 只是安装了java的运行时环境&#xff0c;并不支持编译&#xff0c;安装成…

如何在线批量压缩PDF

PDF格式文档是我们日常比较常用的格式文档之一&#xff0c;那么有什么方法可以减小PDF大小呢&#xff1f;如果PDF比较多是否能批量处理呢&#xff1f; 首先打开浏览器搜索speedpdf就能找到这个在线压缩工具&#xff0c;点击进入后选择PDF压缩可以。如果需要手机和电脑端同步压…

react中Modal组件与openlayers地图实例化在feature要素绘制与清除等场景中存在的bug

在有地图的实际业务中会有一个经常的场景&#xff0c;那就是地图的初始化&#xff0c;一般如下&#xff1a; useEffect(() > {initMap();}, [visible]);我们经常利用Modal组件中open属性状态true与false来作为监听地图初始化的条件。 <Modaltitle{<div className"…

Python导入模块,Python import用法

使用 Python 进行编程时&#xff0c;有些功能没必须自己实现&#xff0c;可以借助 Python 现有的标准库或者其他人提供的第三方库。比如说&#xff0c;在前面章节中&#xff0c;我们使用了一些数学函数&#xff0c;例如余弦函数 cos()、绝对值函数 fabs() 等&#xff0c;它们位…