select 的缺点(水平触发lt)
- 输入参数和输出参数是同一个,就意味着每次调用select都要重新设置
- 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
- select关心的文件描述符是有上限的(底层是位图,有固定大小)
poll 修正了select的两个问题
- poll 将输入输出参数分离
- poll等的文件描述符无上限
poll 的缺点(水平触发lt)
poll中监听的文件描述符数目增多时:
- 和 select 函数一样,poll 返回后,需要轮询 pollfd 来获取就绪的文件描述符
- 每次调用 poll 都需要把大量的 pollfd 结构从用户态拷贝到内核中,开销问题
- 同时连接大量的客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降(poll 没有上限,但是用户也要悠着点)
epoll 的优点(和select的缺点对应)
- 接口使用方便:虽然拆分成了三个函数,但是反而使用起来更方便高效,不需要每次循环都设置关注的文件描述符,也做到了输入输出参数分离
- 数据轻量拷贝:只在合适的时候调用 epoll_ctl_add 将文件描述符结构拷贝到内核中, 这个操作并不频 繁(而 select / poll 都是每次循环都要进行拷贝),开销变的很小
- 事件回调机制:避免使用遍历,而是使用回调函数的方法,将就绪的文件描述符加入到就绪队列中,epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪,这和操作时间复杂度是o(1),即使文件描述符很多,效率也不会受到影响。
- 没有数量限制:文件描述符无上限
但是有一点必须清楚,当连接数不大,并且连接点都处于比较活跃的状态,那么epoll的效率就不如前两者了,毕竟回调通知的方式在大用户量下也会很慢。