select的缺点:
1、单个进程能够监视的文件描述符的数量存在最大限制,通常是1024,当然可以更改数量,但由于select采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;(在linux内核头文件中,有这样的定义:#define __FD_SETSIZE 1024)
2、内核 / 用户空间内存拷贝问题,select每次都会改变内核中的句柄数据结构集,因而每次select调用时都需要从用户空间向内核空间复制所有的句柄数据结构,产生巨大的开销
3、select返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件
4、select的触发方式是水平触发,应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程
epoll实现:
epoll在内核中会维护一个红黑树和一个双向链表,红黑树存放通过epoll_ctl方法向epoll对象中添加进来的事件,所以不需要每次调用epoll_wait都全量复制所有的事件结构。双向链表存放就绪的事件,所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当相应的事件发生时会调用这个回调方法,这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中。调用epoll_wait就会直接返回链表中的就绪事件,效率高。
select适合少量活跃连接,一般几千。
epoll适合大量不太活跃的连接。
如果有大量活跃连接可以使用多进程+select。