区别

· select epoll
实现机制 轮询+内存拷贝+集合 callback+红黑树+mmap+就绪链表
主要消耗 内存拷贝和大量的轮询 callback函数
最大监测FD数 32位系统1024 nolimit
兼容性、跨平台性 POSIX标准 Linux特有
FD增加的影响 性能线性下降 几乎无影响
消息传递方式 内存拷贝 内存映射

表格取自 基于表格形式的select,poll,epoll对比-IO多路复用函数的应用场景

应用场景

从上面的比较可以总结:

select 主要的消耗在于重复的内存拷贝和大量的轮询操作上

epoll 主要的消耗是向内核注册的回调函数上面,文件描述符十分活跃的时候,CPU需要不断的切换上下文,将活跃的FD挂载在链表上,由于有链表的存在使得epoll和poll都可以突破1024

在一开始学习的时候,以为在客户端连接的情况下epoll 都是最好的选择,其实并不然。

当文件描述符在1024以内的时候,select所带来的开支并不会总是epoll 小。

为什么呢?

假设如下场景: 当连接数在1024的时候,这1024条连接全部都是活跃的,时刻都有请求到来,这时候如果使用的是EPOLL,由于EPOLL是事件驱动的,虽然相比于SELECT 避免了FD集合拷贝和轮询的开销,但是频繁的回调函数切换比前者开销更大,同时还需要将活跃的FD插入到链表并将链表拷贝到用户态中,更影响效率。

反观select ,每次拷贝的文件描述符集合大小都是固定的,且轮询操作并不需要涉及到函数切换,在FD活跃的情况下远比EPOLL效率高。

由于限制select效率的最大问题是两次内存拷贝(从用户态到内核态,从内核态到用户态),由于活跃文件描述符过多,EPOLL优势并不明显,相反事件驱动所带来的消耗远比减少一次内存拷贝要来的多。(EPOLL的内存拷贝发生在将就绪链表中的socket拷贝到用户态)