高级I/O知识分享【epoll || Reactor ET,LT模式】

news2024/11/15 13:50:29

   博客主页:花果山~程序猿-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实例添加、修改或删除文件描述符的监听事件。

  • 参数
    • epfdepoll_create返回的epoll文件描述符。
    • op:操作类型,可以是EPOLL_CTL_ADD(添加)、EPOLL_CTL_MOD(修改)、EPOLL_CTL_DEL(删除)。
    • fd:需要操作的文件描述符。
    • event:指向struct epoll_event结构体的指针,包含需要监控的事件类型。

event 事件类型:

  1. EPOLLIN - 表示描述符可读(例如,有数据可读取)。
  2. EPOLLOUT - 表示描述符可写(例如,可以发送数据)。
  3. EPOLLERR - 表示描述符有错误。
  4. EPOLLHUP - 表示描述符挂起(例如,对端关闭了连接)。
  5. EPOLLET - 这是一个边缘触发模式标志,不是事件类型,但它可以与其他事件类型结合使用,以改变事件检测的行为。
  6. EPOLLONESHOT - 这个标志让 epoll_wait() 在第一次匹配到这个事件后就不再为这个文件描述符报告该事件,直到 epoll_ctl() 再次修改此文件描述符的监听条件。
  7. EPOLLEXCLUSIVE - 当设置此标志时,如果多个进程或线程尝试等待同一个事件,那么仅有一个等待者会被唤醒

epoll_wait

epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)

等待已注册文件描述符上的I/O事件发生,并返回就绪事件的数目。

  • 参数
    • epfdepoll_create返回的epoll文件描述符。
    • events:一个指向epoll_event数组的指针,用于返回就绪事件。
    • maxevents:最大可返回的就绪事件数。
    • timeout:等待的超时时间(毫秒为单位)。如果设置为负数或0,则epoll_wait立即返回;如果大于0,则表示等待的时间。

结构体epoll_event: 

从底层原理理解三接口负责的功能图:

当某一进程调用 epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关
struct eventpoll{ 
 .... 
 /*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/ 
 struct rb_root rbr; 
 /*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/ 
 struct list_head rdlist; 
 .... 
};

每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件,这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度). 而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当响应的事件发生时会调用这个回调方法.

这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中.
在epoll中,对于每一个事件,都会建立一个epitem结构体.
struct epitem{ 
 struct rb_node rbn;//红黑树节点 
 struct list_head rdllink;//双向链表节点 
 struct epoll_filefd ffd; //事件句柄信息 
 struct eventpoll *ep; //指向其所属的eventpoll对象 
 struct epoll_event event; //期待发生的事件类型 
}
如果 rdlist 不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户 . 这个操作的时间复杂度是O(1)

如何理解参数epfd的作用?

总结一下, epoll的使用过程就是三部曲: 

  • 调用epoll_create创建一个epoll句柄;
  • 调用epoll_ctl, 将要监控的文件描述符进行注册;
  • 调用epoll_wait, 等待文件描述符就绪;

二,epoll优点(相较select,poll)

  • 接口使用方便: 虽然拆分成了三个函数, 但是反而使用起来更方便高效. 不需要每次循环都设置关注的文件,描述符, 也做到了输入输出参数分离开
  • 数据拷贝轻量: 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中, 这个操作并不频繁(select/poll都是每次循环都要进行拷贝)
  • 事件回调机制: 避免使用遍历, 而是使用回调函数的方式, 将就绪的文件描述符结构加入到就绪队列中, epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪. 这个操作时间复杂度O(1). 即使文件描述符数目很多, 效率也不会受到影响。
  • 没有数量限制: 文件描述符数目无上限

三,epoll2种工作方式

epoll 2 种工作方式 - 水平触发 (LT) 和边缘触发 (ET)

如何理解两种工作方式:(快递员例子)

LT:  当你的外卖(数据)到时,外卖员(底层)会一直给你打电话(通知)直到你下来将你的所有外卖都取走(数据拿走 )。
ET:  外卖来时,外卖员(底层)只给你打一次电话,你如果不下来取,外卖员(底层)不会再通知你,你的外卖(数据)就再也拿不到了。

比较标准的解释:

水平触发Level Triggered 工作模式

epoll 默认状态下就是 LT 工作模式:
  • epoll检测到socket上事件就绪的时候, 可以不立刻进行处理. 或者只处理一部分. 如由于只读了1K数据, 缓冲区中还剩1K数据, 在第二次调用 epoll_wait , epoll_wait 仍然会立刻返回并通知socket读事件就绪. 直到缓冲区上所有的数据都被处理完, epoll_wait 才不会立刻返回.(一直通知你直到数据全部取走)
  • 持阻塞读写和非阻塞读写

边缘触发Edge Triggered工作模式

如果我们在第 1 步将 socket 添加到 epoll 描述符的时候 使用了EPOLLET标志, epoll进入ET工作模式.
  • epoll检测到socket上事件就绪时, 必须立刻处理. 如上面的例子, 虽然只读了1K的数据, 缓冲区还剩1K的数据, 在第二次调用 epoll_wait 的时候, epoll_wait 不会再返回了. 也就是说, ET模式下, 文件描述符上的事件就绪后, 只有一次处理机会.(ET模式下,只有一次处理机会,这样倒逼程序员,要一次取完所有的数据
  • ET的性能LT性能更高( 相同的运行时间内epoll_wait 返回的次数少了很多== 无效通知减少 == 增加其他socket通知的数量). Nginx默认采用ET模式使用epoll.
  • 只支持非阻塞的读写
select poll 其实也是工作在 LT 模式下 . epoll 既可以支持 LT, 也可以支持ET。
LT 情况下如果也能做到每次就绪的文件描述符都立刻处理, 不让这个就绪被重复提示的话 , 其实性能也是一样的 . 但是另一方面, ET 的代码复杂程度更高了。

epoll使用场景

epoll的高性能, 是有一定的特定场景的. 如果场景选择的不适宜, epoll的性能可能适得其反.
  • 对于多连接, 且多连接中只有一部分连接比较活跃时, 比较适合使用epoll.
例如 , 典型的一个需要处理上万个客户端的服务器 , 例如各种互联网 APP的入口服务器 , 这样的服务器就很适合 epoll. 如果 只是系统内部, 服务器和服务器之间进行通信, 只有少数的几个连接, 这种情况下用epoll就并不合适 . 具体要根 据需求和场景特点来决定使用哪种IO 模型。

epoll中的惊群问题(选学)

惊群问题有些面试官可能会问到 . 建议同学们课后自己查阅资料了解一下问题的解决方案。
参考 http://blog.csdn.net/fsmiy/article/details/36873357

 

ET模式使用思路

1.epoll_ctl时添加的文件描述符,需要添加设置 EPOLLET,这样一旦事件就绪,通过epoll_wait报告一次。
2.将需要设置的fd,如listen_socket,设置为非阻塞式;在通过accept系统调用时进行轮询,直到资源被全部提取后,才结束轮询。(采用非阻塞式,就是为了避免一次未取完资源,ET模式下,事件不再通知,导致事件资源丢失)->可参考fcntl接口的非阻塞例子
在优化web服务器为epollET,后面持续更新中...

结语

   本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获,请动动你发财的小手点个免费的赞,你的点赞和关注永远是博主创作的动力源泉。

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

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

相关文章

SpringBoot 消息队列RabbitMQ 消息可靠性 数据持久化 与 LazyQueue

介绍 在默认情况下,RabbitMQ会将接收到的信息保存在内存中以降低消息收发的延迟 一旦MO宕机,内存中的消息会丢失内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发MQ阻塞 在消息队列运行的过程中&#xf…

LeetCode 815.公交路线(BFS广搜 + 建图)(中秋快乐啊)

给你一个数组 routes ,表示一系列公交线路,其中每个 routes[i] 表示一条公交线路,第 i 辆公交车将会在上面循环行驶。 例如,路线 routes[0] [1, 5, 7] 表示第 0 辆公交车会一直按序列 1 -> 5 -> 7 -> 1 -> 5 -> …

物理感知扩散的 3D 分子生成模型 - PIDiff 评测

PIDiff 是一个针对蛋白质口袋特异性的、物理感知扩散的 3D 分子生成模型,通过考虑蛋白质-配体结合的物理化学原理来生成分子,在原理上,生成的分子可以实现蛋白-小分子的自由能最小。 一、背景介绍 PIDiff 来源于延世大学计算机科学系的 Sang…

vue2基础系列教程之v-model及面试高频问题

v-model是表单组件里面的核心知识点&#xff0c;这个指令给我们写表单业务带来了很大的方便。 元素标签上的 v-model 指令用于双向绑定数据,它是一个语法糖&#xff0c;可以用于代替 v-bind:value 和 input 例如&#xff1a;<input v-model"message" placeholder…

VTD激光雷达(6)——06_OptiX_Variables

文章目录 前言一、总结 前言 感谢VTD官方学习资料 一、 1、 总结 学海无涯回头是岸

curl格式化json之jq工具?

jq 是一个轻量级的命令行工具&#xff0c;用于解析、操作和格式化 JSON 数据。它类似于 sed 或 awk&#xff0c;但专门用于处理 JSON 格式。使用 jq&#xff0c;你可以从复杂的 JSON 数据中提取所需的信息&#xff0c;格式化输出&#xff0c;进行数据筛选&#xff0c;甚至修改 …

正点原子阿尔法ARM开发板-IMX6ULL(六)——通过官方SDK完成实验

文章目录 一、引言1.1 cc.h1.2 main.c1.2 fsl_common.h、MCIMX6Y2.h、fsl_iomuxc.h1.3 对于宏定义能多个参数 其他 一、引言 在开发过程中&#xff0c;如果一个人来写寄存器、汇编等东西&#xff0c;会变得特别繁琐&#xff0c;好在官方NXP官方给出了SDK包&#xff0c; 1.1 c…

牛客周赛 Round 60(下)

构造序列 题目描述 登录—专业IT笔试面试备考平台_牛客网 运行代码 #include <iostream> #include<stdio.h> #include<math.h> using namespace std; int main() {int n, m;cin >> n >> m;int minVal min(n, m);int maxVal max(n, m);cout …

如何解决“json schema validation error ”错误? -- HarmonyOS自学6

一. 问题描述 DevEco Studio工程关闭后&#xff0c;再重新打开时&#xff0c;出现了如下错误提示&#xff1a; json schema validation error 原因&#xff1a; index.visual或其他visual文件中的left等字段的值为负数时&#xff0c;不能以”-0.x“开头&#xff0c;否则就会…

了解华为云容器引擎(Cloud Container Engine)

1.什么是云容器引擎&#xff1f; 云容器引擎&#xff08;Cloud Container Engine&#xff0c;简称CCE&#xff09;提供高度可扩展的、高性能的企业级Kubernetes集群。借助云容器引擎&#xff0c;您可以在华为云上轻松部署、管理和扩展容器化应用程序。云容器引擎是一个企业级的…

【Android】使用Room数据库解决本地持久化

【Android】使用Room数据库解决本地持久化 Room概述 Room 是一个持久性库&#xff0c;属于 Android Jetpack 的一部分。 Room 是 SQLite 数据库之上的一个抽象层。Room 并不直接使用 SQLite&#xff0c;而是负责简化数据库设置和配置以及与数据库交互方面的琐碎工作。此外&a…

ElasticSearch-2-核心语法集群高可用实战-Week2

ES批量操作 1.批量获取文档数据 这里多个文档是指&#xff0c;批量操作多个文档&#xff0c;搜索查询文档将在之后的章节讲解 批量获取文档数据是通过_mget的API来实现的 (1)在URL中不指定index和type 请求方式&#xff1a;GET 请求地址&#xff1a;_mget 功能说明 &#…

数据结构 - 树与二叉树

一.普通有序树的定义 1.树的概念及特性 二.二叉树的定义 1.二叉树的性质 2.二叉树的分类 ①.满二叉树 每一层的结点数都为最大值 ②.完全二叉树 完全二叉树是由满二叉树&#xff0c;从下向上&#xff0c;从右向左依次擦除若干个结点 3.二叉树的结构 三.链式二叉树的创建 1.链式…

24-9-17-读书笔记(十八)-《契诃夫文集》(二)上([俄] 契诃夫 [译] 汝龙 )

文章目录 《契诃夫文集》&#xff08;二&#xff09;上&#xff08;[俄] 契诃夫 [译] 汝龙 &#xff09;目录阅读笔记记录总结 《契诃夫文集》&#xff08;二&#xff09;上&#xff08;[俄] 契诃夫 [译] 汝龙 &#xff09; 中秋夜&#xff0c;最近有些忙&#xff0c;看书的进度…

【PHP代码审计】PHP常见配置解析

&#x1f31d;博客主页&#xff1a;菜鸟小羊 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 php.ini配置文件 php函数禁用 disable_functions该选项可以设置哪些php函数是禁止使用的&#xff0c;重启生效&#xff0…

哪款宠物空气净化器能清除浮毛,希喂、米家、美的测评分享

要说市面上评价最为两极分化的家电产品&#xff0c;宠物空气净化器可以说是当仁不让了&#xff0c;几乎一半人说真香&#xff0c;另一半人却在吐槽鸡肋。 作为用过宠物空气净化器实测过市面上多个品牌多款宠物空气净化器产品的专业养宠测评博主&#xff0c;对宠物空气净化器这…

代码随想录:动态规划4-5

42.接雨水 题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,…

PyQt5-QCheckBox-开关按钮

效果预览 实现代码 from PyQt5.QtWidgets import QCheckBox, QApplication, QWidget, QVBoxLayout from PyQt5.QtCore import Qt, QRect, QPropertyAnimation, QEasingCurve, pyqtProperty from PyQt5.QtGui import QPainter, QColor, QPen, QFontclass CompactSwitchCheckbox…

PostgreSQL维护——解决索引膨胀和数据死行

注意&#xff1a; 本文内容于 2024-09-16 00:40:33 创建&#xff0c;可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容&#xff0c;请访问原文地址&#xff1a;PostgreSQL维护——解决索引膨胀和数据死行。感谢您的关注与支持&#xff01; 我有一张表&#…

Python3网络爬虫开发实战(17)爬虫的管理和部署(第一版)

文章目录 一、 Scrapyd 分布式部署1.1 了解 Scrapyd1.2 准备工作1.3 访问 Scrapyd1.4 Scrapyd 的功能1.5 ScrapydAPI 的使用 二、Scrapyd-Client 的使用2.1 准备工作2.2 Scrapyd-Client 的功能2.3 Scrapyd-Client 部署 三、Scrapyd 对接 Docker3.1 准备工作3.2 对接 Docker 四、…