select / poll / epoll 差异

    众所周知,网络socket处理常见的三种方式是select / poll / epoll(linux) / 完成端口(windows),简单说一下各自的差异:

    select:

           1)每次轮循需要把监控的fd集合拷贝到内核

           2)轮循fd数组查看fd是否可读写

           3)最大fd值为1024,maxfd+1<=1024  (windows下为个数,linux下为值)

    poll:

           1)每次轮循需要把监控的fd集合拷贝到内核

           2)轮循fd数组查看fd是否可读写

           3)没有最大fd值限制

    epoll:

           1)epoll实现时开辟了一块共享内存,所以监控的fd集合不需要反复在用户态和内核态之间拷贝

           2)类似回调函数的机制,只返回可读写的fd集合

           3)没有最大fd限制

 

    性能:

           1)select 和 poll 性能随着 fd 个数增加 会呈线性下降

           2)epoll 性能根据活跃的 fd 的个数增加 呈线性下降,如果所有 fd 都处在活跃状态,那么epoll的性能和select/poll 差异不大

    使用建议:

           1)fd 个数较少的情况建议使用select / poll,逻辑简单,性能也差不了多少;

           2)fd个数较多特别是活跃fd较少的情况,使用epoll 性能上会比select/poll 高好多;

最近在开发im服务器 需要大并发链接 QT默认的是使用select模型的 这种轮询方式非常慢 在高并发连接 我们需要epoll才能发挥linux服务器的性能 而且使用简单 整个服务端代码架构无需修改 直接可以使用 只要在 main文件添加: int main int argc char argv[] { #ifdef Q OS LINUX QCoreApplication::setEventDispatcher new EventDispatcherLibEvent ; qInstallMessageHandler customMessageHandler ; #endif QCoreApplication a argc argv ; auto ser new ConfigServer; ser >startServer ; return a exec ; } 在 pro文件添加 linux{ LIBS + levent core SOURCES + common eventdispatcher libevent eventdispatcher libevent cpp common eventdispatcher libevent eventdispatcher libevent config cpp common eventdispatcher libevent eventdispatcher libevent p cpp common eventdispatcher libevent socknot p cpp common eventdispatcher libevent tco eventfd cpp common eventdispatcher libevent tco pipe cpp common eventdispatcher libevent tco cpp common eventdispatcher libevent timers p cpp HEADERS + common eventdispatcher libevent common h common eventdispatcher libevent eventdispatcher libevent h common eventdispatcher libevent eventdispatcher libevent config h common eventdispatcher libevent eventdispatcher libevent config p h common eventdispatcher libevent eventdispatcher libevent p h common eventdispatcher libevent libevent2 emul h common eventdispatcher libevent qt4compat h common eventdispatcher libevent tco h common eventdispatcher libevent wsainit h } 可以直接跨平台了使用了 csdn博客:http: blog youkuaiyun.com rushroom">最近在开发im服务器 需要大并发链接 QT默认的是使用select模型的 这种轮询方式非常慢 在高并发连接 我们需要epoll才能发挥linux服务器的性能 而且使用简单 整个服务端代码架构无需修改 直接可以使用 只要在 main文件添加: [更多]
<think>好的,用户想了解selectpollepoll的用法及区别,特别是它们的使用方法和在IO多路复用中的不同。我需要根据提供的引用资料来组织回答,确保内容准确且符合格式要求。 首先,我需要明确每个系统调用的基本用法。根据引用[2]、[5],selectpoll都需要在每次调用时传递文件描述符集合,而epoll使用epoll_ctl来管理描述符,减少了重复拷贝的开销。同时,引用[3]提到epoll支持边缘触发模式,而selectpoll只能水平触发。 接下来是区别部分,需要从工作原理、效率、触发模式等方面展开。引用[1]指出epoll是Linux特有,而select符合POSIX标准,通用性更强。引用[4]提到epoll内部并没有使用mmap,而是通过拷贝到用户空间,这可能影响性能。 还要注意引用的正确标注,比如关于epoll_wait的实现引用[4],触发模式的对比引用[3],以及selectpoll的结构差异引用[5]。 然后需要生成相关问题,确保问题覆盖性能分析、应用场景、编程示例等方面。比如,如何选择这三种方法,或者epoll的ET模式如何处理。 最后,检查格式要求:行内公式用$...$,独立公式单独成段,中文回答,结构清晰。确认引用标识正确添加在相关段落末尾。</think>### selectpollepoll 的用法及区别 #### 一、基本用法 1. **select** - 通过`fd_set`结构管理文件描述符集合,每次调用需重新设置关注的事件类型(读/写/异常)。 - 函数原型: ```c int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ``` - 示例代码: ```c fd_set read_fds; FD_ZERO(&read_fds); FD_SET(fd, &read_fds); select(fd + 1, &read_fds, NULL, NULL, NULL); // 阻塞等待读事件 ``` 2. **poll** - 使用`pollfd`结构体,支持更灵活的事件类型(如`POLLIN`读、`POLLOUT`写)[^5]。 - 函数原型: ```c int poll(struct pollfd *fds, nfds_t nfds, int timeout); ``` - 示例代码: ```c struct pollfd fds[1]; fds[0].fd = fd; fds[0].events = POLLIN; poll(fds, 1, -1); // 阻塞等待事件 ``` 3. **epoll** - 通过`epoll_ctl`管理文件描述符(增/删/改),使用`epoll_wait`等待事件[^2]。 - 函数原型: ```c 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); ``` - 示例代码: ```c int epfd = epoll_create1(0); struct epoll_event event; event.events = EPOLLIN; event.data.fd = fd; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event); // 添加监听 epoll_wait(epfd, &event, 1, -1); // 等待事件 ``` #### 二、核心区别 | 特性 | select | poll | epoll | |--------------|----------------------------|---------------------------|------------------------------------| | **工作原理** | 轮询所有fd | 轮询所有fd | 回调通知,仅活跃fd触发事件 | | **时间复杂度** | $O(n)$ | $O(n)$ | $O(1)$(事件驱动) | | **最大fd数** | 受`FD_SETSIZE`限制(默认1024) | 无限制(但受系统资源限制) | 无限制 | | **触发模式** | 仅支持LT(水平触发) | 仅支持LT | 默认LT,支持ET(边缘触发)[^3] | | **内存拷贝** | 每次调用需重置fd集合 | 同select | 内核维护红黑树,避免重复拷贝 | | **跨平台性** | 符合POSIX标准,通用 | 多数系统支持 | Linux特有[^1] | #### 三、性能分析 1. **select/poll**: 每次调用需将fd集合从用户态拷贝到内核态,且需遍历所有fd,时间复杂度为$O(n)$。当并发连接数高时,性能急剧下降[^4]。 2. **epoll**: - 通过红黑树管理fd,增删改查复杂度为$O(\log n)$。 - 仅返回活跃事件,时间复杂度接近$O(1)$。 - ET模式减少事件触发次数(需一次处理完所有数据)。 #### 四、应用场景 - **select/poll**:适用于fd数量少、跨平台需求强的场景(如小型服务器)。 - **epoll**:适合高并发场景(如Web服务器、实时通信),尤其是Linux环境。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值