首页 > 其他分享 >【IO复用】select、poll、epoll的区别

【IO复用】select、poll、epoll的区别

时间:2025-01-16 17:57:10浏览次数:3  
标签:文件 epoll 描述符 内核 IO poll select

目录

啥是IO复用

  • 在传统阻塞 IO 模式下,每个线程会阻塞等待一个 fd(文件描述符或套接字描述符等)的就绪状态,导致需要大量的线程,资源消耗高。
  • IO复用,就是一个线程可以监视多个 fd,一旦某个 fd 准备就绪(可读、可写或异常),就可以对其进行对应的 IO 操作;就不用每个 fd 都开个线程去等着,做到高效的处理更多IO请求。

有了IO复用的需求,接下来我们看看在Linux下如何实现


select

  • select 是把所有的文件描述符列表交给内核,让内核帮忙检查哪些文件有事件发生
  • 它就像是个小本子,每次让系统内核帮你看着的时候,都要把小本子的内容从你的地方(用户态)抄一遍给系统(内核态)
  • 过程:
    1. 用户程序将需要监听的文件描述符集合(fd_set)传给内核。
    2. 内核会轮询所有文件描述符,检查它们是否有事件发生。
    3. 如果有事件发生,select 返回,用户程序需要手动遍历 fd_set 找出触发事件的文件。
    4. 每次调用 select 都需要重新设置 fd_set,因为返回后 fd_set 的内容会被内核修改。
  • select 还有文件描述符数量限制,一般是最大只能监听 1024 个(可以通过修改 FD_SETSIZE 来增加)

poll

  • 跟 select 类似,也需要把所有文件交给内核;不过它的机制更灵活(用一个结构体数组)
  • poll 有点像升级版的 select,不过没有 select 的 1024 个文件描述符的限制
  • 过程:
    1. 用户程序将文件描述符和对应事件的数组传给内核。
    2. 内核轮询数组中的所有文件描述符,检查是否有事件发生。
    3. 如果有事件发生,poll 返回,用户程序需要遍历数组,找出哪些描述符触发了事件。
    4. 与 select 不同,poll 的数组内容不会被内核清空,可以直接重复使用。

epoll

  • epoll 就聪明多了,你把要关注的文件告诉 epoll,它就在自己的地方(内核里)记下来;当有数据来了,它会自动把消息放到一个队列里,你只需要去队列里拿消息就行。
  • 过程:
    1. 使用 epoll_create 创建一个 epoll 实例,内核为其分配一个数据结构来管理文件描述符。
    2. 通过 epoll_ctl 将要监听的文件描述符添加到 epoll 实例中。
    3. 内核维护一个内部的 事件队列,当有事件发生时,内核会将该文件描述符的事件加入队列中。
    4. 程序调用 epoll_wait 来获取队列中已经准备好的文件描述符和它们的事件

为啥 select 和 poll 需要遍历

select

  • Select 使用 fd_set 数据结构来管理文件集合,fd_set 本质上是一个位图,当调用select函数后,内核会检查这些文件描述符的状态,将就绪的文件描述符在位图中标记出来。
  • Select 函数返回后,不会直接告诉你是哪些描述符就绪,所以应用程序需要遍历之前设置的 fd_set 集合,通过 FD_ISSET 宏来逐个检查每个文件描述符是否在就绪集合中。

poll

  • poll 使用 pollfd 结构体数组来管理文件描述符。每个pollfd结构体包含文件描述符、要监听的事件和实际发生的事件等信息
  • 当poll函数返回后,内核会在每个 pollfd 的 revents 字段中标记出实际发生的事件,但是 poll 不会直接告诉你具体是哪个文件描述符的哪个事件就绪了,所以应用程序需要遍历整个 pollfd 数组,检查每个 pollfd 的 revents

epoll

  • epoll 不需要遍历
  • 因为,内核在文件描述符就绪时,会主动将其放入一个就绪队列中,用户程序调用 epoll_wait 时,直接从这个就绪队列取,所以,无需遍历其它文件描述符。

为什么用 select 和 poll 时·内核·需要去轮询

历史原因

  • select 是一种非常早期的设计,当时的需求和场景相对简单,轮询的的成本在当时是可以接受的。
  • poll 是对 select 的改进,支持更大的文件描述符集合,但仍需轮询。
  • 随着系统并发量的增加和对性能要求的提高,epoll 顺时而生。

调度机制

  • 核心问题:
    • 硬件中断可以告诉内核“某个设备有新数据到达了”,但内核还需要知道这个设备是对应哪个文件描述符(多个文件描述符可能指向相同类型的设备)
  • 而 select 和 poll 不保存与文件描述符的长期关联关系
  • 内核在硬件中断或事件发生时,无法主动通知是哪些文件描述符发生了变化
  • 所以它们必须从用户传递过来的文件描述符集合中一个一个去检查。

epoll 如何知道是哪个文件描述符有变化?

  • 在调用 epoll_ctl 注册文件描述符时,内核会将文件描述符和监听事件关联起来
  • 内核会为每个文件描述符绑定协议栈或驱动中的回调函数
  • 当设备状态变化(如网卡接收数据)时,硬件中断触发回调函数,通知协议栈解析,定位到具体的文件文件描述符
  • 如果文件描述符的状态满足监听条件,内核会将其加入 epoll 的事件队列

所以,主要原因就是在用 select 和 poll 时,内核并没有利用协议栈和驱动的回调机制,这意味着,内核在收到硬件中断时,无法定位到具体的文件描述符,必须轮询来确认。

总结

  • select 和 poll:需要用户态和内核态频繁交互,且依赖内核轮询,效率较低
  • epoll:借助回调机制和就绪队列,避免了内核轮询和用户态遍历,大幅提升性能

标签:文件,epoll,描述符,内核,IO,poll,select
From: https://blog.csdn.net/BitBool/article/details/145166622

相关文章

  • Flutter使用FractionallySizedBox组件报错Failed assertion: line 2164 pos 12: 'hasS
    这里从解决方法那里直接给出个有效的方式。就是如果你使用了FractionallySizedBox组件,第一是这个组件只能在固定宽高下或者Row,Flex,Column组件下使用。第二就是这个组件需要在Flexible下使用.结构就是:Row->Flexible->FractionallySizedBox给出简单的代码示例......
  • SpelExpressionParser 是 Spring Expression Language(SpEL)中的一个重要组件,用于解析
    SpelExpressionParser 是SpringExpressionLanguage(SpEL)中的一个重要组件,主要用于解析和评估Spring表达式。以下是关于它的详细解释:主要功能表达式解析:将一个以字符串形式表示的Spring表达式转换为可执行的表达式对象。Spring表达式可以包含变量引用、方法调用、属性......
  • F. Array Stabilization (AND version)
    题目链接:Problem-1579F-Codeforces题目大意:给一个n,dn表示数组的长度,d表示每次将数组向右移动的长度,列入d=2,数组:12345,那么下一次移动过后的数组为45123.由于数组只包含0与1,要求让移动过后的数组与前一个数组做AND运算,求多少次可以将数组变为全0,如果不能输......
  • H1. Maximize the Largest Component (Easy Version)
    题目链接:Problem-H1-Codeforces题目大意:给一个由‘.'与’#‘的字符组合成的二维矩阵,现在又有一种操作可以使每一列或每一行全部变成’#‘,然后求这个二维矩阵里的由’#‘组合成的最大连通块,求出该最大连通块的大小。输入的第一行包含一个整数 tt(1≤t≤1e4 )-测试用......
  • ViewDataDictionary(this.ViewData)
    在ASP.NETMVC中,ViewDataDictionary是一个用于在控制器和视图之间传递数据的字典类。它继承自ViewDataContainer,并提供了键值对的存储和检索功能。ViewDataDictionary可以存储任何类型的数据,并且在视图中可以通过键名来访问这些数据。构造函数 ViewDataDictionary(this.ViewD......
  • (14-3-02)基于Latent Diffusion Transformer的文生视频系统:数据集处理(2)加载并处理Taic
    6.4.3 加载并处理Taichi数据集文件taichi_datasets.py实现了一个Taichi数据集类,用于加载和处理分帧存储的视频数据,特别是太极表演相关的帧序列。它包括从数据目录中读取视频帧、按时间进行帧采样、将帧数据转换为张量并应用数据增强等功能。代码通过torch.utils.data.Da......
  • BEVFusion: Multi-Task Multi-Sensor Fusion with Unified Bird’s-Eye View Represen
    多传感器融合最近的方法为将相机特征与激光雷达点云进行融合。然而,相机到激光雷达的投影会丢失相机特征的语义密度,阻碍此类方法的效果,尤其是对于语义导向的任务(如3D场景分割)。BEVFusion,将多模态特征统一在共享的鸟瞰视图(BEV)表示空间中,同时保持了几何结构和语义密度,并......
  • 本次小论文minor revision中的知识积累
    可以发邮件向编辑申请延期返修截止日期https://cn.service.elsevier.com/app/answers/detail/a_id/29653/c/10595/supporthub/publishing/role/作者/https://zhuanlan.zhihu.com/p/577324425申请邮件模板:如何在EditorialManager系统中提交修改稿?【爱思唯尔Editorial......
  • 在Gitea中运行Actions demo时,遇到node报错
    错误信息node[39]:../src/node_platform.cc:68:std::unique_ptr<longunsignedint>node::WorkerThreadsTaskRunner::DelayedTaskScheduler::Start():Assertion`(0)==(uv_thread_create(t.get(),start_thread,this))'failed.1:0xb9c1f0node::Abort()[no......
  • 解析function(_0x457ace, _0x349832) 即random出处
    function(_0x457ace,_0x349832){ _0x457ace=_0x457ace-0x18a; var_0x4c6e1a=_0x19971f[_0x457ace]; if(a0_0x457a['pIaRKj']===undefined){ var_0x2a073e=function(_0x3f86c9){ var_0x153ef8='abcdefghijklmnopqrstuvwxyzABCDEFGH......