详解IO多路复用机制——select、poll、epoll的原理和区别

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

🌟 前言

🐶 大家好,我是周周,目前就职于国内短视频小厂BUG攻城狮一枚。
🤺 如果文章对你有帮助,记得关注、点赞、收藏,一键三连哦,你的支持将成为我最大的动力。

🍑 1 概述

select、poll 以及 epoll 是 Linux 系统的三个系统调用,也是 IO 多路复用模型的具体实现。

前文 五种常见IO模型我们可以知道,IO 多路复用就是通过一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作的一种机制。

IO 多路复用的优点

与多进程和多线程技术相比,IO 多路复用技术的最大优势是系统开销小,系统不必创建进程或线程,也不必维护这些进程,从而大大减小了系统的开销。

主流 IO 多路复用机制的基准测试

🍑 2 select

#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
          const struct timeval *timeout);
// return:表示此时有多少个监控的描述符就绪,若超时则为0,出错为-1。

select 函数监视的文件描述符分三类,分别是 writefds、readfds 和 exceptfds。

select 调用过程

1)用户进程需要监控某些资源 fds,在调用 select 函数后会阻塞,操作系统会将用户线程加入这些资源的等待队列中。

2)直到有描述副就绪(有数据可读、可写或有 except)或超时(timeout 指定等待时间,如果立即返回设为 null 即可),函数返回。

3)select 函数返回后,中断程序唤起用户线程。用户可以遍历 fds,通过 FD_ISSET 判断具体哪个 fd 收到数据,并做出相应处理。

select 函数优点明显,实现起来简单有效,且几乎所有操作系统都有对应的实现。

select 的缺点

1)每次调用 select 都需要将进程加入到所有监视 fd 的等待队列,每次唤醒都需要从每个队列中移除。 这里涉及了两次遍历,而且每次都要将整个 fd_set 列表传递给内核,有一定的开销。

2)当函数返回时,系统会将就绪描述符写入 fd_set 中,并将其拷贝到用户空间。进程被唤醒后,用户线程并不知道哪些 fd 收到数据,还需要遍历一次。

受 fd_set 的大小限制,32 位系统最多能监听 1024 个 fd,64 位最多监听 2048 个。

🍑 3 poll

int poll(struct pollfd* fds, int nfds, int timeout);
/*
struct pollfd{
	int fd;        // 感兴趣fd
	short events;  // 监听事件
	short revents; // 就绪事件
};
*/
// return:表示此时有多少个监控的描述符就绪,若超时则为0,出错为-1。

poll 函数与 select 原理相似,都需要来回拷贝全部监听的文件描述符,不同的是:

1)poll 函数采用链表的方式替代原来 select 中 fd_set 结构,因此可监听文件描述符数量不受限

2)poll 函数返回后,可以通过 pollfd 结构中的内容进行处理就绪文件描述符,相比 select 效率要高。

3)新增水平触发:也就是通知程序 fd 就绪后,这次没有被处理,那么下次 poll 的时候会再次通知同个 fd 已经就绪。

poll 缺点

和 select 函数一样,poll 返回后,需要轮询 pollfd 来获取就绪的描述符。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

🍑 4 epoll

epoll 在 2.6 内核中提出,是之前的 select 和 poll 的增强版。

int epoll_create(int size)//创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

epoll 使用一个文件描述符管理多个描述符,将用户进程监控的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间只需拷贝一次。

🍉 4.1 函数定义

  • epoll_create

创建一个 epoll 的句柄,参数 size 并非限制了 epoll 所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。

当 epoll 句柄创建后,它就会占用一个 fd 值,在 linux 中查看/proc/进程id/fd/,能够看到这个 fd,所以 epoll 使用完后,必须调用 close() 关闭,否则可能导致 fd 被耗尽。

  • epoll_ctl

事件注册函数,将需要监听的事件和需要监听的 fd 交给 epoll 对象。

OP 用三个宏来表示:添加(EPOLL_CTL_ADD)、删除(EPOLL_CTL_DEL)、修改(EPOLL_CTL_MOD)。分别表示添加、删除和修改 fd 的监听事件。

struct epoll_event {
  __uint32_t events;  /* Epoll events */
  epoll_data_t data;  /* User data variable */
};

//events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里

通过 epoll_ctl 函数添加进来的事件都会被放在红黑树的某个节点内,所以,重复添加是没有用的。

当把事件添加进来的时候时候会完成关键的一步,那就是该事件都会与相应的设备驱动程序建立回调关系,当相应的事件发生后,就会调用这个回调函数,该回调函数在内核中被称为 ep_poll_callback,这个回调函数其实就所把这个事件添加到 rdllist 这个双向链表中。一旦有事件发生,epoll 就会将该事件添加到双向链表中。那么当我们调用 epoll_wait 时,epoll_wait 只需要检查 rdlist 双向链表中是否有存在注册的事件,效率非常可观。这里也需要将发生了的事件复制到用户态内存中即可。

上图我们可以看出,所有 FD 集合采用红黑树存储,就绪 FD 集合使用链表存储。这是因为就绪 FD 都需要处理,业务优先级需求,最好的选择便是线性数据结构。

  • epoll_wait

等待 epfd 上的 io 事件,最多返回 maxevents 个事件。参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。

1)epoll_wait调用ep_poll,当rdlist为空(无就绪fd)时挂起当前进程,直到rdlist不空时进程才被唤醒。

2)文件fd状态改变(buffer由不可读变为可读或由不可写变为可写),导致相应fd上的回调函数ep_poll_callback()被调用。

3)ep_poll_callback将相应fd对应epitem加入rdlist,导致rdlist不空,进程被唤醒,epoll_wait得以继续执行。

4)ep_events_transfer函数将rdlist中的epitem拷贝到txlist中,并将rdlist清空。

5)ep_send_events函数(很关键),它扫描txlist中的每个epitem,调用其关联fd对用的poll方法。此时对poll的调用仅仅是取得fd上较新的events(防止之前events被更新),之后将取得的events和相应的fd发送到用户空间(封装在struct epoll_event,从epoll_wait返回)。

🍉 4.2 工作模式

1)LT模式

LT(level triggered)模式:也是默认模式,即当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件,并且下次调用 epoll_wait 时,会再次响应应用程序并通知此事件。

2)ET模式

ET(edge-triggered)模式:当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。

ET 是一种高速工作方式,很大程度上减少了 epoll 事件被重复触发的次数。epoll 工作在 ET 模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

🍉 4.3 为何高效

1) epoll 精巧的使用了 3 个方法来实现 select 方法要做的事,分清了频繁调用和不频繁调用的操作。

epoll_ctrl 是不太频繁调用的,而 epoll_wait 是非常频繁调用的。而 epoll_wait 却几乎没有入参,这比 select 的效率高出一大截,而且,它也不会随着并发连接的增加使得入参越发多起来,导致内核执行效率下降。

2) mmap 的引入,将用户空间的一块地址和内核空间的一块地址同时映射到相同的一块物理内存地址(不管是用户空间还是内核空间都是虚拟地址,最终要通过地址映射映射到物理地址),使得这块物理内存对内核和对用户均可见,减少用户态和内核态之间的数据交换。

3)红黑树将存储 epoll 所监听的 FD。高效的数据结构,本身插入和删除性能比较好,时间复杂度O(logN)。

🍑 5 总结

三种函数在的 Linux 内核里有都能够支持,其中 epoll 是 Linux 所特有,而 select 则应该是 POSIX 所规定,一般操作系统均有实现。

🍉 5.1 三种机制的区别

摘录自《linux高性能服务器编程》

🍉 5.2 epoll 优点

1)没有最大并发连接的限制,能打开的 FD 的上限远大于 1024。

2)效率提升,不是轮询的方式,不会随着 FD 数目的增加效率下降。

3)内存拷贝,利用 mmap() 文件映射内存加速与内核空间的消息传递,即 epoll 使用 mmap 减少复制开销。

4)新增 ET 模式。

selectpollepoll详解 selectpollepoll详解 1.IO复用 为了解决大量客户端访问的问题,引入IO复用技术:一个进程可以同时对多个客户请求进行服务,复用一个进程对多个IO进行服务。IO读写的数据多数情况下未准备好,需要通过一个函数监听这些数据状态,一旦有数据可以读写就触发服务。elect,poll,epoll都是IO多路复用机制,监视多个描述符,一旦某个描述符就绪,通知程序进行操作。 2.select 3.poll 4.epoll epollLinux平台下的一种特有的多路复用IO实现方式,与传统的 sel 阅读详情

相关推荐

selectpollepoll区别

是三种 I/O 多路复用机制,用于高效管理多个文件描述符的 I/O 事件。)管理描述符集合,每次调用需将整个集合从用户空间拷贝到内核,内核遍历所有描述符检测就绪状态。:基于事件驱动,内核维护红黑树存储监控的描述符,就绪事件通过双向链表返回。:需非阻塞 I/O 并一次性读取数据,减少系统调用次数,适合高性能场景。:仅在状态变化时通知一次,需一次性处理所有数据。:仅处理就绪事件,性能几乎不受连接数影响。:需结合非阻塞 I/O,避免漏处理事件。:可能重复通知就绪事件,适合简单场景。:只要描述符就绪,持续通知。

HL_LOVE_C的博客 1259

epollpollselect原理区别

一、什么是epollepoll是一种I/O事件通知机制,是linux 内核实现IO多路复用的一个实现。IO多路复用是指,在一个操作里同时监听多个输入输出源,在其中一个或多个输入输出源可用的时候返回,然后对其的进行读写操作。 epoll有两种工作方式,ET-水平触发 LT-边缘触发(默认工作方式),主要区别是: LT,内核通知你fd是否就绪,如果没有处理,则会持续通知。而ET,内核只通知一次。 二、epoll的三个函数 int epoll_create(int size) size参数告诉内核这

wwwvipp的博客 5万+

I/O 多路复用select()、poll()、epoll()详解

I/O 多路复用select==>时间复杂度O(n)poll==>时间复杂度O(n)epoll==>时间复杂度O(1)epoll的接口介绍epoll的工作模式epollselect/poll的对比epoll的优点 selectpollepoll都是IO多路复用机制。I/O多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但selectpollepoll本质上都是同步I/O,因为他们都需要在读写事件

TABE_的博客 4231

selectpollepoll原理区别

转载: selectpollepoll原理区别 IO复用 selectpollepoll都是IO复用的基本实现,select出现的最后,之后是poll,再是epollSelect 我们使用select就可以实现同时处理多个网络连接的IO请求,基本原理就是程序调用select,然后整个程序就进入阻塞状态,这个时候,kernel内核就会轮询检查所有select负责的文件描述符fd,当找到其中哪个数据准备好了文件描述符,会返回给selectselect通知系统调用,将数据从内核复制到进程的缓存区

sususuqingxiao的博客 3752

IO多路复用epollselect区别

IO多路复用epollselect区别IO多路复用epollselectepoll,poll,select总结 IO多路复用 什么是IO多路复用,假设有1000个文件或者网络IO需要我们处理,这里统称为IO,无论IO是否阻塞,总需要有线程去等待IO的完成,那么难道有1000个IO,就要去开1000个线程去监听吗,这样做资源浪费太过严重,所以不同的系统提供了不同的IO多路复用selectpollepoll) I/O 多路复用被用来处理同一个事件循环中的多个 I/O 事件。I/O 多路复用需要使用特

清风 1485

LV9 详解IO多路复用机制——selectpollepoll原理区别

🐶 大家好,我是周周,目前就职于国内短视频小厂BUG攻城狮一枚。🤺 如果文章对你有帮助,,你的支持将成为我最大的动力。selectpoll 以及epollLinux 系统的三个系统调用,也是 IO 多路复用模型的具体实现。由前文 五种常见IO模型我们可以知道,IO多路复用就是通过一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作的一种机制IO 多路复用的优点。

m0_46112340的博客 211

Linux 系统编程 13:IO 多路复用

本文深入讲解了高并发网络编程的核心技术——IO多路复用。首先分析了传统多进程/线程模型在高并发场景下的性能瓶颈,然后系统介绍了三种IO多路复用实现:selectpollepoll。重点剖析了epoll的红黑树+就绪链表机制、水平触发(LT)边沿触发(ET)模式的区别,并给出了ET模式的正确使用规范。通过性能对比指出epoll在监听数量、数据拷贝、查找效率等方面的优势,最后总结了面试高频考点常见易错点。

x1649545783的博客 339

IO 模型

IO 模型的核心区分点是「数据准备阶段是否阻塞」「是否需要用户线程等待 IO 完成」,同步异步关注全程,阻塞非阻塞关注数据准备阶段。BIO 是基础但低效,NIO 多路复用解决了 C10K 问题(主流方案),AIO 理论最优但落地成本高。实际开发无需手写原生 IO 模型,优先选择 Netty 等成熟框架,底层依赖 NIO 多路复用即可满足绝大多数高并发场景。

2503_92804185的博客 145

Linux网络最终篇:TCP并发服务器

本文探讨了TCP并发服务器的核心挑战与实现方案。传统迭代服务器无法同时处理多客户端请求,主要存在阻塞问题。解决方案包括:1)多进程/线程模型,主线程负责接收连接,子线程处理通信,但资源消耗大;2)高效的I/O多路复用模型(select/poll/epoll),其中epollLinux下的最优选择,通过事件驱动机制实现单线程高效处理多连接。文章详细介绍了epoll的三个关键函数(create/ctl/wait)事件循环机制,并提供了C语言实现代码,展示了epoll如何解决阻塞困境,成为构建高性能网络服务的

2302_80623234的博客 892

【JAVA】IO多路复用selectpollepoll详解

文章内容1、概述2、selector3、poll4、epoll5、selectpollepoll区别 1、概述 I/O 多路复用技术通过把多个 I/O 的阻塞复用到同一个 select 的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程/多进程模型比,I/O 多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程线程的运行,降低了系统的维护工作量,节省了系统资源。 其应用场景如下: 服务器需要同时处理多个处于监听状态或者多个连接状态的套

fearless的博客 4023

IO多路复用selectpollepoll之间的区别总结

selectpollepoll都是IO多路复用机制IO多路复用就是通过一种机制,让一个进程/线程可以监视多个描述符,一旦某个描述符就绪(一般是读写就绪),能够通知应用程序进行相应的读写操作。I/O复用虽然能同时监听多个文件描述符,当其本质上还是同步IO模型,因为需要在读写事件就绪后程序自己负责进行读写事件的处理,而这个读写过程是阻塞的。如果要实现并发,只能使用多进程/多线程等编程手段了。 ...

yunfan 2771

IO多路复用机制——selectpollepoll原理区别

selectpollepoll都是IO多路复用机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。问题:如果我们先前创建的几个进程承载不了目前快速发展的业务的话,是不是还得增加进程数?我们都知道系统创建进程是需要消耗大量资源的,所以这样就会导致系统资源不足的情况。那么有没有一种方式可以让一个进程同时为多个客户端端提供服务?

Liu___l的博客 2660

SelectpollepollIO多路复用NIO

SelectPollEpoll 是实现 IO 多路复用的不同技术手段,各有其性能特点适用场景,而 NIO 是 Java 中应用 IO 多路复用思想的一种实现,它与这些 IO 多路复用技术紧密相关,并且在不同的操作系统下会依托不同的 IO 多路复用实现方式来实现其功能。

qq_62097431的博客 2014

IO多路复用selectpollepoll之间的区别

1、支持一个进程所能打开的最大连接数单个进程所能打开的最大连接数有FD_SETSIZE宏定义,其大小是32个整数的大小(在32位的机器上,大小就是3232,同理64位机器上FD_SETSIZE为3264),当然我们可以对进行修改,然后重新编译内核,但是性能可能会受到影响,这需要进一步的测试。poll本质上select没有区别,但是它没有最大连接数的限制,原因是它是基于链表来存储的虽然连接数有上限,但是很大,1G内存的机器上可以打开10万左右的连接,2G内存的机器可以打开20万左右的连接。

欢迎来到 程序猿 的博客 2363

selectpollepoll原理

select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait() 时便得到通知。(此处去掉了遍历文件描述符,而是通过监听回调的的机制。这正是epoll的魅力所在。epoll的优点主要是一下几个方面:1.监视的描述符数量不受限制,它所支持的FD上限是最大可以打开文件的数目。

m0_45164511的博客 1508

【netty系列-06】深入理解selectpollepoll多路复用区别

深入理解selectpollepoll多路复用区别

zhenghuishengq的博客 2396

IO多路复用selectpollepoll

Linux之五种IO模型中,我们介绍了说 IO多路复用包含三种机制selectpollepoll,本篇文章就来区分一下他们。 其中B站这个up主讲的非常好【并发】IO多路复用select/poll/epoll介绍 一、几个概念 1.1、用户空间内核空间 现在操作系统都是采用虚拟存储器,那么对于32位操作系统而言,他的寻址空间(虚拟存储空间)为4G。操作系统的核心是内核,独立于普通的应用程序...

weixin_42579072的博客 4000

IO多路复用(select poll epoll)

IO多路复用是高性能网络编程一个重要的手段之一。一,IO多路复用的概念 以前我们用多线程来处理并发的请求,现在可以只用单线程来实现。单线程,通过记录跟踪每个每个I/O流(sock)的状态,来达到同时管理多个I/O流的目的,提高了服务器的吞吐能力。 如图所示,IO多路复用,就如同中间的开关,哪个sock就绪就连上开关,达到了单开关处理了多个I/O流的目的。这就是单线程却能处理多个Sock传

染尘 4676

IO多路复用——Select, Poll, Epoll详解

本文详细介绍了I/O多路复用的三种实现方式:selectpollepoll。主要内容包括:1. I/O多路复用概念:通过单线程管理多个网络连接,突破多线程模型的性能瓶颈。2. select详解:使用位图(fd_set)管理fd,存在1024个连接限制O(n)扫描开销。3. poll改进:采用pollfd数组突破连接数限制,但性能模型与select类似。4. epoll优势:通过红黑树就绪队列实现高效事件通知,支持大并发连接。5. 三者对比:epoll性能最优但仅限Linuxselect/poll

qq_43727159的博客 1120
上一篇: 五种常见IO模型
下一篇: 【MySQL】进阶——一起探究MySQL优化器如何选择索引的奥秘
程序猿周周
程序猿周周 新星创作者: Java技术领域 新星创作者: Java技术领域
博客等级 码龄10年 1万+粉丝 125原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿周周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值