Epoll,Poll,Select模型比较

本文对比分析了网络编程中的三种核心技术:Select、Poll与Epoll,阐述了它们在Socket数量限制、操作限制等方面的区别,并讨论了在不同应用场景下选择最优技术的重要性。特别强调了反射机制在Epoll中的高效性及其局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载自: http://www.iteye.com/topic/469644

 

先说Select:
1.Socket数量限制:该模式可操作的Socket数由FD_SETSIZE决定,内核默认32*32=1024.
2.操作限制:通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍.

后说Poll:
1.Socket数量几乎无限制:该模式下的Socket对应的fd列表由一个数组来保存,大小不限(默认4k).
2.操作限制:同Select.

再说:Epoll:
1.Socket数量无限制:同Poll
2.操作无限制:基于内核提供的反射模式,有活跃Socket时,内核访问该Socket的callback,不需要遍历轮询.

总体来说:
大部分情况下,反射的效率都比遍历来的高,但是!
但是当所有Socket都活跃的时候,反射还会更高么?这时候所有的callback都被唤醒,会导致资源的竞争.既然都是要处理所有的Socket,那么遍历是最简单最有效的实现方式.

举例来说:
对于IM服务器,服务器和服务器之间都是长链接,但数量不多,一般一台60\70个,比如采用ICE这种架构设计,但请求相当频繁和密集,这时候通过反射唤醒callback不一定比用select去遍历处理更好.
对于web portal服务器,都是浏览器客户端发起的http短链接请求,数量很大,好一点的网站动辄每分钟上千个请求过来,同时服务器端还有更多的闲置等待超时的Socket,这时候没必要把全部的Socket都遍历处理,因为那些等待超时的请求是大多数的,这样用Epoll会更好.

### C语言中epollpollselect的区别对比 在C语言的网络编程中,`epoll`、`poll` 和 `select` 是三种常用的I/O多路复用技术,用于同时监视多个文件描述符的状态变化。以下是它们的主要区别: #### 1. **实现机制** - **select**:通过轮询所有文件描述符来检查是否有事件发生。每次调用 `select` 都需要将所有感兴趣的文件描述符传递给内核[^4]。 - **poll**:与 `select` 类似,但使用了 `pollfd` 结构体数组来管理文件描述符,避免了 `select` 的某些限制(如文件描述符数量受限于 `FD_SETSIZE`)。 - **epoll**:基于事件驱动模型,通过内核中的红黑树和双向链表优化了性能。它只需要在添加或删除文件描述符时与内核交互,减少了不必要的上下文切换[^1]。 #### 2. **文件描述符数量限制** - **select**:受限于系统定义的 `FD_SETSIZE` 常量,通常为 1024。 - **poll**:理论上没有文件描述符数量的限制,但实际受系统资源约束。 - **epoll**:没有明确的文件描述符数量限制,仅受限于系统内存[^1]。 #### 3. **性能表现** - **select**:每次调用都需要将所有的文件描述符集合复制到内核空间,并且返回后需要逐一检查每个文件描述符的状态,效率较低[^4]。 - **poll**:虽然解决了 `select` 的文件描述符数量限制问题,但其轮询机制仍然会导致性能瓶颈,尤其是在大量文件描述符的情况下。 - **epoll**:采用事件就绪通知的方式,只有当某个文件描述符有事件发生时才会通知用户程序,极大地提高了性能。 #### 4. **API接口** - **select**: ```c int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ``` 需要手动管理 `fd_set` 集合,并且每次调用都需要重新设置感兴趣的状态[^4]。 - **poll**: ```c int poll(struct pollfd *fds, nfds_t nfds, int timeout); ``` 使用 `pollfd` 结构体数组,操作更加灵活,但仍然需要每次调用都传递完整的数组。 - **epoll**: - 创建实例:`int epoll_create(int 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` 提供了更清晰的接口分离,使得代码逻辑更加简洁[^1]。 #### 5. **适用场景** - **select**:适用于文件描述符较少的简单场景,适合初学者学习和理解 I/O 多路复用的基本原理。 - **poll**:适合文件描述符较多但对性能要求不高的场景,可以作为 `select` 的替代方案[^4]。 - **epoll**:适用于高并发、高性能的网络服务器开发,尤其在 Linux 平台上具有显著优势[^1]。 ```python # 示例代码:epoll 使用示例 import socket import select import epoll # 创建 epoll 实例 ep = epoll.epoll_create(1) # 添加监听的 socket 文件描述符 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost', 8080)) sock.listen(5) epoll.epoll_ctl(ep, epoll.EPOLL_CTL_ADD, sock.fileno(), epoll.epoll_event(epoll.EPOLLIN)) # 等待事件 events = epoll.epoll_wait(ep, 10, -1) for fileno, event in events: if fileno == sock.fileno(): conn, addr = sock.accept() epoll.epoll_ctl(ep, epoll.EPOLL_CTL_ADD, conn.fileno(), epoll.epoll_event(epoll.EPOLLIN)) ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值