epoll poll select区别

本文深入探讨了epoll的工作原理,对比了select、poll和epoll的优劣,详细解析了epoll如何通过高效的回调机制和内核用户空间的内存映射,解决传统I/O多路复用技术的痛点。

select :

1.每次调用 select(),都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大,同时每次调用 select() 都需要在内核遍历传递进来的所有 fd,这个开销在 fd 很多时也很大。

2.单个进程能够监视的文件描述符的数量存在最大限制,在 Linux 上一般为 1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低

 

 

poll:

select() 和 poll() 系统调用的本质一样,poll() 的机制与 select() 类似,与 select() 在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是 poll() 没有最大文件描述符数量的限制(但是数量过大后性能也是会下降)。poll() 和 select() 同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。

 

 

epoll:

epoll 是在 2.6 内核中提出的,是之前的 select() 和 poll() 的增强版本。相对于 select() 和 poll() 来说,epoll 更加灵活,没有描述符限制。epoll 使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的 copy 只需一次。

copy一次

回调

 

 

总结:

与select相比,epoll的回调机制使得资源能够直接使用在有活动的事件上,而不用线性轮询所有的事件。同时 epoll通过内核与用户空间mmap同一块内存,减少了用户空间和内核空间的数据交换,解决了select的重要痛点。

另一方面,LT是epoll的默认操作模式,当epoll_wait函数检测到有事件发生并将通知应用程序,而应用程序不一定必须立即进行处理,这样epoll_wait函数再次检测到此事件的时候还会通知应用程序,直到事件被处理。

而ET模式,只要epoll_wait函数检测到事件发生,通知应用程序立即进行处理,后续的epoll_wait函数将不再检测此事件。因此ET模式在很大程度上降低了同一个事件被epoll触发的次数,因此效率比LT模式高。

### 三、EpollPollSelect 的 I/O 多路复用技术对比 #### 1. 文件描述符数量限制 - `select` 使用固定大小的位掩码(`fd_set`)来表示文件描述符集合,默认最大支持的文件描述符数为 1024,这个限制可以通过重新编译内核来调整,但通常不推荐[^4]。 - `poll` 使用动态分配的文件描述符数组,理论上没有文件描述符数量的硬性限制,但实际受限于系统资源。 - `epoll` 没有文件描述符数量的限制,并且在内部使用红黑树结构高效管理大量文件描述符,适用于高并发场景[^4]。 #### 2. 性能与效率 - `select` 每次调用都需要将文件描述符集合从用户空间复制到内核空间,且每次调用后都需要重新初始化集合,导致性能随着连接数增加而下降。 - `poll` 虽然不需要每次都重新初始化文件描述符集合,但仍然需要将整个描述符数组从用户空间复制到内核空间,且每次返回时都需要遍历所有描述符以确定哪些就绪,效率较低。 - `epoll` 通过事件驱动机制,仅将就绪的文件描述符返回给用户空间,避免了不必要的复制遍历操作,因此在大规模并发连接下性能显著优于 `select` `poll`[^4]。 #### 3. 使用方式与 API - `select` 提供了 `select()` 函数,使用 `fd_set` 结构体管理文件描述符,支持可读、可写、异常事件的监控。 - `poll` 使用 `pollfd` 结构数组,每个结构体包含文件描述符事件掩码,调用 `poll()` 函数进行事件监控。 - `epoll` 提供了三个核心函数: - `epoll_create()`:创建一个 epoll 实例。 - `epoll_ctl()`:添加、修改或删除监听的文件描述符。 - `epoll_wait()`:等待事件发生并返回就绪的文件描述符列表。 示例代码:使用 `epoll` 的基本结构如下: ```c int epollfd = epoll_create(1); // 创建 epoll 实例 struct epoll_event ev, events[10]; ev.events = EPOLLIN; // 监听可读事件 ev.data.fd = sockfd; epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev); // 添加监听 int nfds = epoll_wait(epollfd, events, 10, -1); // 等待事件 for (int i = 0; i < nfds; ++i) { if (events[i].events & EPOLLIN) { // 处理可读事件 } } ``` #### 4. 内核实现机制 - `select` `poll` 都采用轮询机制,每次调用时都需要遍历所有文件描述符来检查状态。 - `epoll` 使用回调机制,在文件描述符状态发生变化时,由内核主动通知 `epoll`,从而避免了轮询的开销。 #### 5. 适用场景 - `select`:适合连接数较少、对性能要求不高的场景,尤其在跨平台兼容性方面表现较好。 - `poll`:适合连接数较多但并发压力不大的情况,相比 `select` 更具灵活性。 - `epoll`:专为高并发场景设计,广泛应用于 Linux 网络服务器,如 Nginx、Redis 等高性能服务中。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值