高级I/O知识分享【epoll || Reactor ET,LT模式】
博客主页:花果山~程序猿-CSDN博客
文章分栏:Linux_花果山~程序猿的博客-CSDN博客
关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长!
目录
一,接口
epoll_create
epoll_ctl
event 事件类型:
epoll_wait
二,epoll优点(相较select,poll)
三,epoll有2种工作方式
如何理解两种工作方式:(快递员例子)
水平触发Level Triggered 工作模式
边缘触发Edge Triggered工作模式
epoll使用场景
epoll中的惊群问题(选学)
ET模式使用思路
嗨!收到一张超美的图,愿你每天都能顺心!
一,接口
epoll_create
epoll_create(size_t size)
用于创建一个epoll
文件描述符,返回一个非负整数表示新创建的epoll
实例的文件描述符。size
是一个建议值,表示最初能容纳多少个事件,但实际上内核可能会忽略此参数。
- 参数:
size
:建议的初始事件槽的数量,但在现代内核版本中此参数几乎无用,内核会根据需要动态调整。
epoll_ctl
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
用于向epoll
实例添加、修改或删除文件描述符的监听事件。
- 参数:
epfd
:epoll_create
返回的epoll
文件描述符。op
:操作类型,可以是EPOLL_CTL_ADD
(添加)、EPOLL_CTL_MOD
(修改)、EPOLL_CTL_DEL
(删除)。fd
:需要操作的文件描述符。event
:指向struct epoll_event
结构体的指针,包含需要监控的事件类型。
event 事件类型:
- EPOLLIN - 表示描述符可读(例如,有数据可读取)。
- EPOLLOUT - 表示描述符可写(例如,可以发送数据)。
- EPOLLERR - 表示描述符有错误。
- EPOLLHUP - 表示描述符挂起(例如,对端关闭了连接)。
- EPOLLET - 这是一个边缘触发模式标志,不是事件类型,但它可以与其他事件类型结合使用,以改变事件检测的行为。
- EPOLLONESHOT - 这个标志让 epoll_wait() 在第一次匹配到这个事件后就不再为这个文件描述符报告该事件,直到 epoll_ctl() 再次修改此文件描述符的监听条件。
- EPOLLEXCLUSIVE - 当设置此标志时,如果多个进程或线程尝试等待同一个事件,那么仅有一个等待者会被唤醒
epoll_wait
epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
等待已注册文件描述符上的I/O事件发生,并返回就绪事件的数目。
- 参数:
epfd
:epoll_create
返回的epoll
文件描述符。events
:一个指向epoll_event
数组的指针,用于返回就绪事件。maxevents
:最大可返回的就绪事件数。timeout
:等待的超时时间(毫秒为单位)。如果设置为负数或0,则epoll_wait
立即返回;如果大于0,则表示等待的时间。
结构体epoll_event:
从底层原理理解三接口负责的功能图:
struct eventpoll{ .... /*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/ struct rb_root rbr; /*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/ struct list_head rdlist; ....
};
每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件,这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度). 而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当响应的事件发生时会调用这个回调方法.
struct epitem{ struct rb_node rbn;//红黑树节点 struct list_head rdllink;//双向链表节点 struct epoll_filefd ffd; //事件句柄信息 struct eventpoll *ep; //指向其所属的eventpoll对象 struct epoll_event event; //期待发生的事件类型
}
如何理解参数epfd的作用?
总结一下, epoll的使用过程就是三部曲:
- 调用epoll_create创建一个epoll句柄;
- 调用epoll_ctl, 将要监控的文件描述符进行注册;
- 调用epoll_wait, 等待文件描述符就绪;
二,epoll优点(相较select,poll)
- 接口使用方便: 虽然拆分成了三个函数, 但是反而使用起来更方便高效. 不需要每次循环都设置关注的文件,描述符, 也做到了输入输出参数分离开
- 数据拷贝轻量: 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中, 这个操作并不频繁(而select/poll都是每次循环都要进行拷贝)
- 事件回调机制: 避免使用遍历, 而是使用回调函数的方式, 将就绪的文件描述符结构加入到就绪队列中, epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪. 这个操作时间复杂度O(1). 即使文件描述符数目很多, 效率也不会受到影响。
- 没有数量限制: 文件描述符数目无上限
三,epoll有2种工作方式
如何理解两种工作方式:(快递员例子)
LT: 当你的外卖(数据)到时,外卖员(底层)会一直给你打电话(通知)直到你下来将你的所有外卖都取走(数据拿走 )。ET: 外卖来时,外卖员(底层)只给你打一次电话,你如果不下来取,外卖员(底层)不会再通知你,你的外卖(数据)就再也拿不到了。
比较标准的解释:
水平触发Level Triggered 工作模式
epoll 默认状态下就是 LT 工作模式:
- 当epoll检测到socket上事件就绪的时候, 可以不立刻进行处理. 或者只处理一部分. 如由于只读了1K数据, 缓冲区中还剩1K数据, 在第二次调用 epoll_wait 时, epoll_wait 仍然会立刻返回并通知socket读事件就绪. 直到缓冲区上所有的数据都被处理完, epoll_wait 才不会立刻返回.(一直通知你直到数据全部取走)
- 支持阻塞读写和非阻塞读写
边缘触发Edge Triggered工作模式
- 当epoll检测到socket上事件就绪时, 必须立刻处理. 如上面的例子, 虽然只读了1K的数据, 缓冲区还剩1K的数据, 在第二次调用 epoll_wait 的时候, epoll_wait 不会再返回了. 也就是说, ET模式下, 文件描述符上的事件就绪后, 只有一次处理机会.(ET模式下,只有一次处理机会,这样倒逼程序员,要一次取完所有的数据)
- ET的性能比LT性能更高( 相同的运行时间内epoll_wait 返回的次数少了很多== 无效通知减少 == 增加其他socket通知的数量). Nginx默认采用ET模式使用epoll.
- 只支持非阻塞的读写
epoll使用场景
- 对于多连接, 且多连接中只有一部分连接比较活跃时, 比较适合使用epoll.
epoll中的惊群问题(选学)
ET模式使用思路
1.epoll_ctl时添加的文件描述符,需要添加设置 EPOLLET,这样一旦事件就绪,通过epoll_wait报告一次。2.将需要设置的fd,如listen_socket,设置为非阻塞式;在通过accept系统调用时进行轮询,直到资源被全部提取后,才结束轮询。(采用非阻塞式,就是为了避免一次未取完资源,ET模式下,事件不再通知,导致事件资源丢失)——>可参考fcntl接口的非阻塞例子例如:这个监听套接字的例子
选择ET和LT
选择哪种模式取决于具体的应用场景和需求。如果你的应用程序需要处理大量并发连接,并且对实时性要求较高,那么 ET 模式可能是更好的选择。如果你的应用程序需要处理长时间存在的连接,并且更关注稳定性,那么 LT 模式可能是更好的选择。
用ET模式优化自主web服务器
Apache 和 Nginx 是两款广泛使用的 Web 服务器软件,它们在处理大量并发连接方面表现出色。为了实现高效的并发处理,这两款服务器都利用了 Linux 内核提供的高性能 I/O 多路复用机制 epoll
。
- Apache:通常使用 Level Triggered (LT) 模式,因为它提供了更好的稳定性和易用性。
- Nginx:通常使用 Edge Triggered (ET) 模式,因为它提供了更高的性能和实时性。
框架图

优化心得总结
读事件思维逻辑:
epoll
的事件队列中,随后用户可以通过不断轮询 epoll_wait
函数来获取并处理这些事件(如处理方法监听套接字上的 accept
操作)。
写事件思维逻辑:
当一个套接字的发送缓冲区满时,写操作会被阻塞。内核维护了一个发送缓冲区的状态,当缓冲区中有足够的空间可以写入数据时,内核会将该文件描述符标记为可写(即 EPOLLOUT
事件就绪)。
关于写事件逻辑理解:
1. 刚连接时是否需要设置写事件?
当一个套接字刚刚建立连接时,通常情况下发送缓冲区是有空间的。但是,为了确保应用程序能够及时响应写操作,通常的做法是在连接建立后立即设置写事件。这样做有几个好处:
- 立即响应:如果发送缓冲区确实有空间,那么设置写事件可以确保应用程序能够立即响应写操作。这有助于提高应用的响应速度。
- 预防缓冲区满的情况:即使当前缓冲区有空间,设置写事件可以防止未来缓冲区满时错过写事件。在 ET 模式下,如果没有设置写事件,当缓冲区满时,应用程序将不会收到
EPOLLOUT
事件,从而可能导致数据积压。
2. 在写操作被阻塞时设置写事件?
如果你在写操作被阻塞时才设置写事件,可能会导致以下问题:
- 事件丢失:在 ET 模式下,如果写操作被阻塞,并且在设置写事件之前缓冲区有了空间,那么这个事件可能会被丢失。因为 ET 模式只会报告一次事件,除非应用程序显式地清除事件状态。
- 延迟响应:如果在写操作被阻塞时才设置写事件,可能会导致响应延迟。因为此时缓冲区已经有空间了,但应用程序还没有设置写事件,所以不会立即得到通知。
3. 刚连接时设置写事件是否会立即触发一次写事件?
当一个套接字刚刚建立连接时,发送缓冲区通常有空间。在这种情况下,设置写事件确实可能会立即触发一次写事件。然而,这是预期的行为,处理起来比较简单。
异常事件逻辑:
在epoll的ET模式下,想要主要触发异常事件(如:EPOLLERR ,EPOLLHUP),可以制造错误条件达到目的。比如通过主动close文件描述符,那么EPOLLHUP事件会被触发。
总结一下:
LT(水平触发):
-
EPOLLIN 触发条件:
读缓冲区有数据就一直触发(即epoll_wait时能检测到),没有就不触发。 -
EPOLLOUT 触发条件:
写缓冲区有空间可写,则一直触发。
ET(边缘触发)
EPOLLIN 触发条件:
1. 当读 buff 从 空 -> 不空 时,触发;
2. 当有新数据到达时,即读 buff 数据由 少 -> 多 时,触发;
3. 当读 buff 有数据可读时,我们不处理,但是对相应fd进行epoll_ctl重新注册epoll_mod IN事件时,触发。
EPOLLOUT 触发条件:
1. 当写 buff 从 满 -> 不满 时,触发;
2. 当有数据被送走时,即写 buff 数据由 多 -> 少 时,触发;
3. 当写 buff 有数据,但是我们没处理(没发送出去),但是对相应fd进行epoll_ctl重新注册epoll_mod OUT事件时,触发。
结语
本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获,请动动你发财的小手点个免费的赞,你的点赞和关注永远是博主创作的动力源泉。
相关文章:

高级I/O知识分享【epoll || Reactor ET,LT模式】
博客主页:花果山~程序猿-CSDN博客 文章分栏:Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长! 目录 一,接口 epo…...

Matlab 的.m 文件批量转成py文件
在工作中碰到了一个问题,需要将原来用matlab gui做出来的程序改为python程序,因为涉及到很多文件,所以在网上搜了搜有没有直接能转化的库。参考了【Matlab】一键Matlab代码转python代码详细教程_matlab2python-CSDN博客 这位博主提到的matla…...

【软考】传输层协议TCP与UDP
目录 1. TCP1.1 说明1.2 三次握手 2. UDP3. 例题3.1 例题1 1. TCP 1.1 说明 1.TCP(Transmission Control Protocol,传输控制协议)是整个 TCP/IP 协议族中最重要的协议之一。2.它在IP提供的不可靠数据服务的基础上为应用程序提供了一个可靠的、面向连接的、全双工的…...

Arthas dashboard(当前系统的实时数据面板)
文章目录 二、命令列表2.1 jvm相关命令2.1.1 dashboard(当前系统的实时数据面板) 二、命令列表 2.1 jvm相关命令 2.1.1 dashboard(当前系统的实时数据面板) 使用场景: 在 Arthas 中,dashboard 命令用于提…...

微服务保护之熔断降级
在微服务架构中,服务之间的调用是通过网络进行的,网络的不确定性和依赖服务的不可控性,可能导致某个服务出现异常或性能问题,进而引发整个系统的故障,这被称为 微服务雪崩。为了防止这种情况发生,常用的一些…...

TomCat乱码问题
TomCat控制台乱码问题 乱码问题解决: 响应乱码问题 向客户端响应数据: package Servlet;import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servl…...

依赖库查看工具Dependencies
依赖库查看工具:Dependencies Dependencies 是一款 Windows 平台下的静态分析工具,用来分析可执行文件(EXE、DLL 等)所依赖的动态链接库(DLL)。它可以帮助开发者和系统管理员快速查找程序在运行时可能缺少的…...

Kafka 下载安装及使用总结
1. 下载安装 官网下载地址:Apache Kafka 下载对应的文件 上传到服务器上,解压 tar -xzf kafka_2.13-3.7.0.tgz目录结果如下 ├── bin │ └── windows ├── config │ └── kraft ├── libs ├── licenses └── site-docs官方文档…...

python实现多个pdf文件合并
打印发票时,需要将pdf合并成一个,单页两张打印。网上一些pdf合并逐渐收费,这玩意儿都能收费?自己写一个脚本使用。 实现代码: 输入pdf文件夹路径data_dir,统计目录下的“合并后的PDF”文件夹下,…...
2409js,学习js2
原文 全局对象 function sayHi() {alert("Hello"); }// 全局对象的函数. window.sayHi(); alert(window.innerHeight);更改背景 document.body.style.background "red";setTimeout(() > document.body.style.background "", 1000);当前地…...

SpellBERT: A Lightweight Pretrained Model for Chinese Spelling Check(EMNLP2021)
SpellBERT: A Lightweight Pretrained Model for Chinese Spelling Check(EMNLP2021) 一.概述 作者认为许多模型利用预定义的混淆集来学习正确字符与其视觉上相似或语音上相似的误用字符之间的映射,但映射可能是域外的。为此,我们提出了SpellBERT&…...

【机器学习】--- 决策树与随机森林
文章目录 决策树与随机森林的改进:全面解析与深度优化目录1. 决策树的基本原理2. 决策树的缺陷及改进方法2.1 剪枝技术2.2 树的深度控制2.3 特征选择的优化 3. 随机森林的基本原理4. 随机森林的缺陷及改进方法4.1 特征重要性改进4.2 树的集成方法优化4.3 随机森林的…...

[SAP ABAP] 创建域
我们可以使用事务码SE11创建域 输入要创建的域的名称,然后点击创建 输入简短描述,选择数据类型和输入字符数 激活并保存域,创建的域才能够生效 补充扩展练习 创建一个有关"性别"基本信息的域...

STM32 通过 SPI 驱动 W25Q128
目录 一、STM32 SPI 框图1、通讯引脚2、时钟控制3、数据控制逻辑4、整体控制逻辑5、主模式收发流程及事件说明如下: 二、程序编写1、SPI 初始化2、W25Q128 驱动代码2.1 读写厂商 ID 和设备 ID2.2 读数据2.3 写使能/写禁止2.4 读/写状态寄存器2.5 擦除扇区2.6 擦除整…...

C#进阶-基于雪花算法的订单号设计与实现
在现代电商系统和分布式系统中,高效地生成全局唯一的订单号是一个关键需求。订单号不仅需要唯一性,还需要具备一定的趋势递增性,以满足数据库索引和排序的需求。本文将介绍如何在C#中使用雪花算法(Snowflake)设计和实现…...

低版本SqlSugar的where条件中使用可空类型报语法错误
SQLServer数据表中有两列可空列,均为数值类型,同时在数据库中录入测试数据,Age和Height列均部分有值。 使用SqlSugar的DbFirst功能生成数据库表类,其中Age、Height属性均为可空类型。 开始使用的SqlSugar版本较低&…...

跨游戏引擎的H5渲染解决方案(腾讯)
本文是腾讯的一篇H5 跨引擎解决方案的精炼。 介绍 本文通过实现基于精简版的HTML5(HyperText Mark Language 5)来屏蔽不同引擎,平台底层的差异。 好处: 采用H5的开发方式,可以将开发和运营分离,运营部门自…...
docker构建java镜像,运行镜像出现日志 no main manifest attribute, in /xxx.jar
背景 本文主要是一个随笔,记录一下出现"no main manifest attribute"的解决办法 问题原因 主要是近期在构建一个镜像,在镜像构建成功后,运行一直提示"no main manifest attribute",当时还在想,是不是Dockerfile写错了,后来仔细检查了一下,发现是…...

react + antDesignPro 企业微信扫码登录
效果 实现步骤 1、项目中document.ejs文件引入企微js链接 注意:技术栈是使用的react antDesignPro,不同的技术栈有不同的入口文件(如vue在html文件引入) <script src"https://wwcdn.weixin.qq.com/node/wework/wwopen/j…...

Go-知识-定时器
Go-知识-定时器 1. 介绍2. Timer使用场景2.1 设定超时时间2.2 延迟执行某个方法 3. Timer 对外接口3.1 创建定时器3.2 停止定时器3.3 重置定时器3.4 After3.5 AfterFunc 4. Timer 的实现原理4.1 Timer数据结构4.1.1 Timer4.1.2 runtimeTimer 4.2 Timer 实现原理4.2.1 创建Timer…...

【alluxio编译报错】Some files do not have the expected license header
Some files do not have the expected license header 快捷导航 在开始解决问题之前,大家可以通过下面的导航快速找到相关资源啦!💡👇 快捷导航链接地址备注相关文档-ambaribigtop自定义组件集成https://blog.csdn.net/TTBIGDA…...

基于SpringBoot+Vue的商城积分系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、SSM项目源码 精品专栏:Java精选实战项目源码、Python精…...

docker-compose up 报错:KeyError: ‘ContainerConfig‘
使用命令查看所有容器: docker ps -a 找到有异常的容器删除 docker rm {容器id} 后续发现还是会出现这种情况,尝试使用更高版本的docker-compose后解决...
股票行情接口,量化金融交易在未来会被广泛应用吗
炒股自动化:申请官方API接口,散户也可以 python炒股自动化(0),申请券商API接口 python炒股自动化(1),量化交易接口区别 Python炒股自动化(2):获取…...
[SDX35+WCN6856]SDX35 开启class/gpio子系统配置操作说明
SDX35 SDX35介绍 SDX35设备是一种多模调制解调器芯片,支持 4G/5G sub-6 技术。它是一个4nm芯片专为实现卓越的性能和能效而设计。它包括一个 1.9 GHz Cortex-A7 应用处理器。 SDX35主要特性 ■ 3GPP Rel. 17 with 5G Reduced Capability (RedCap) support. Backward compati…...

react:React Hook函数
使用规则 只能在组件中或者其他自定义的Hook函数中调用 只能在组件的顶层调用,不能嵌套在if、for、 其他函数中 基础Hook 函数 useState useState是一个hook函数,它允许我们向组件中添加一个状态变量,从而控制影响组件的渲染结果 示例1…...

算法学习2
学习目录 一.插入排序 一.插入排序 从数组的第一个元素开始,当前元素与其前一个元素进行比较; 大于(或小于时)将其进行交换,即当前元素替换到前一位; 再将该元素与替换后位置的前一个元素进行交换…...

vue循环渲染动态展示内容案例(“更多”按钮功能)
当我们在网页浏览时,常常会有以下情况:要展示的内容太多,但展示空间有限,比如我们要在页面的一部分空间中展示较多的内容放不下,通常会有两种解决方式:分页,“更多”按钮。 今天我们的案例用于…...
好用的工具网址
代码类: 1,json解析:JSON在线解析及格式化验证 - JSON.cn 2.传参转化编码 在线url网址编码、解码器-BeJSON.com 日常: 1.莆田医院查询:滚蛋吧!莆田系...
【Temporal】方法规范
在workflow或者childWorkflow的方法代码中,不能使用golang的一些库方法,比如sleep,go协程等,必须使用其对应的封装方法,比如对应关系如下: time.Sleep -> workflow.Sleepgo xx -> workflow.Go(xx) 这…...