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

多路转接之epoll的两种触发方式(LT,ET的效率对比,原理,epoll读取数据的过程)

目录

EPOLL的触发方式

水平触发 LT(Level Triggered)

边沿触发 ET(Eage Triggered)

比喻

过程

总结

回到epoll

效率

为什么要一次读完?

如何确保读完了所有数据?

举例

回到epoll

效率对比总结

本质


epoll接口介绍 -- epoll接口介绍,epoll模型介绍+原理,接口和模型的关系,epoll优点(和select/poll进行对比)-CSDN博客

EPOLL的触发方式

水平触发 LT(Level Triggered)

epoll的默认方式

  • 如果我们没有处理[已就绪的事件],会一直通知我们

可以把已就绪的事件看作高电平,通知看作有效

  • 水平触发就是,只要处于高电平,就有效

边沿触发 ET(Eage Triggered)

数据/连接有变化的时候,才会通知,且只通知一次

  • 变化 -- 从无到有,从有到多

 

比喻

过程

可以把这两个模式看做是两个快递员送货的方式

  • a快递员 -- 当有快递送到,而你不去取/取了一部分,会一直打电话通知让你来取,直到取完
  • b快递员 -- 也会在快递送到时通知,区别在于:如果你没有取/只取了一部分,他不会将剩下的部分留在那里,而是带走 ; 并且他这次通知了之后就不管了,直到有新快递到来,才又会通知我们,然后带上之前你剩下的快递

总结

乍眼一看,可能会觉得a方式更好

但因为b的特性,如果我们没有一次取完,可能导致货物丢失什么的,或是等待下一个货物等待了很久

  • 所以,会倒逼我们在收到通知后,就一次取走所有货物

并且,对比a和b,我们会发现,b可以通知到更多的人

  • 因为一个快递员在一定时间内打出的电话次数是有限的
  • a可能一直在打重复电话,而b通知到的人数更多

回到epoll

效率

也就是说:

  • ET的特性会倒逼程序员,在处理通知时,需要一次将收到的数据全部读取,否则会错过这一次发来的完整数据,直到对方向我们发来新的数据,才能接收到上一轮剩下的数据
  • 所以,ET的io效率更高 -- 通知一次,就把数据全部取走

联系到tcp层:

  • 如果一次就能把数据全部取走,接收缓冲区就会更大的空间,从而向对方发送一个更大的窗口,这样对方一次就能发送更多的数据(和延迟应答的原理类似)

因为ET下可以通知更多的进程

  • 所以通知效率也更高

为什么要一次读完?

如果不强制要求,可能会导致通信双方无法完成正常通信

  • 假设,a收到了b的10k数据,但a只读取了1k,剩下的还在内核缓冲区里
  • 然后就会卡在这里: a在等待b的通知,想要继续读取数据 ; 而b在等待a的应答,收到应答后才会继续发送数据
  • 这就尴尬了
  • 所以,必须一次读完

如何确保读完了所有数据?

举例

假如a月初领了1000块,到了月中的时候,你找他借钱,此时你并不知道他现在有多少钱

如果你想把他手里的钱全部借走,怎么做?

  • 可以先借100,如果要多少给多少,说明他手里还有钱,可以继续要
  • 直到给的比要的少,有零有整的,说明此时已经要完了
  • 如果此时再继续要,他就会说自己已经没有钱了
回到epoll

总结一下就是 -- 保证全部取走 = 循环读取,直到没有数据

注意:

  • 如果是阻塞io,recv/read函数在没有数据可以读取的情况下,会阻塞至有数据到达
  • 但这不是我们希望的,因为我们写的是个单进程,一旦阻塞,整个服务器就寄了
  • 所以,我们要在ET模式下设置为非阻塞模式

我们之前实验过,如果当前没有数据,会返回[错误码为11]的错误

效率对比总结

但并不是说ET的效率就一定比LT方式高

  • 普遍情况下,确实是这样的,但还是取决于代码的具体实现

谁说采用了LT模式就不能将所有fd设置为非阻塞方式,然后循环读取,直到没有数据呢?

  • 如果我们保证在LT模式下,在第一次通知时,就取走全部数据,也就达到了和ET一样的效果
  • 只不过一个是主动,一个是被动这么做

本质

前面我们一直在说的通知,其本质是 -- 添加结点入就绪队列

  • 只要上层调用epoll_wait,就能获取队列中的数据

当然,如果不调用也没办法

  • 毕竟内核也不能强迫调用接口吧,通知就是它能做到的极限了
  • 就像tcp中的psh标志,他也只是催促对方赶紧将收到的数据准备好交给上层,而无法硬塞给上层

epoll读取数据的流程:

  • 就是等就绪队列有数据+调用epoll_wait接口 -> 将就绪队列中的数据读取到tcp层的接收缓冲区中 -> 上层从缓冲区中读出数据(读出的方式就是ET和LT的区别)
  • LT -- 不保证一次读完,但每次都会将未被读取的结点放入队列
  • ET -- 因为只会将结点放入队列中一次,所以必须读完数据

http://www.kler.cn/news/312260.html

相关文章:

  • 算法基础-二分查找
  • 2025秋招LLM大模型多模态面试题(六)-KV缓存
  • 亿级数据表多线程update锁表问题
  • 浅谈人工智能之基于ollama本地大模型结合本地知识库搭建智能客服
  • 2024最新版,人大赵鑫老师《大语言模型》新书pdf分享
  • 嵌套函数的例子(TypeScript)
  • QT QObject源码学习(二)
  • Netty源码解析-请求处理与多路复用
  • uniapp中使用picker-view选择时间
  • vulhub搭建漏洞环境docker-compose up -d命令执行报错以及解决方法汇总
  • 信息收集常用指令
  • PDF样本册如何分享到朋友圈
  • Qt自定义信号、带参数的信号、lambda表达式和信号的使用
  • elemntui el-switch 在表格内改变状态失败,怎么复原???
  • 一文读懂SpringCLoud
  • 【RabbitMQ 项目】服务端数据管理模块之交换机管理
  • prometheus监控linux虚拟机
  • 操作系统迁移(CentOs -> Ubuntu)
  • Wacom 和 Splashtop 携手共赴 IBC 2024 展会,宣布向欧洲市场隆重推出 Wacom Bridge
  • XSS漏洞挖掘利用总结(附个人常用payload)
  • MyBatis 分批次执行(新增,修改,删除)
  • ROS激光雷达介绍
  • WPF中图片的宫格显示
  • TPDO触发条件如何满足?
  • AI学习指南深度学习篇-Adam的Python实践
  • 如何配置和使用自己的私有 Docker Registry
  • python的6种常用数据结构
  • 3.大语言模型LLM的公开资源(API、语料库、算法库)
  • Python中的树与图:构建复杂数据结构的艺术
  • 图论三元环(并查集的高级应用)