select
select是将所有的描述符状态保存进fd_set中,然后遍历fd_set的状态变化来进行相应的操作。它的主要缺点有:
- 采用轮询的方式遍历所有描述符的状态,当数量较多时效率低下;
- 单个进程支持最大并发连接的数量有限,通常为1024个;
- 大量的fd_set数据结构需要从用户到内核的不断拷贝,效率低;
- 大量高并发时使用多个进程实现还需要进程上下文切换的开销;
- 如果触发了某个描述符这次没有处理,那么下次仍然会触发。
- 平台支持广
poll
poll跟select一样也是需要轮询描述符状态来实现,主要的区别在于poll是使用链表来保存多个描述符的监听,所以就没有了最大连接限制,但仍然效率低下。
epoll
epoll对于每一个创建的epoll对象都会维护一个红黑树和一个双链表,红黑树存储着所有添加到epoll中需要监控的描述符,而双链表则存放着将要通过epoll_wait返回给用户的满足条件的描述符,而epoll_wait则又采用了回调的方式将触发的描述符返回给用户,除此之外epoll还使用了内存映射的方式将添加的描述符映射到内核空间(内存共享),避免了拷贝的代价。因此epoll的并发高效性远远优于select和poll,但是有一点必须清楚,当连接数不大,并且连接点都处于比较活跃的状态,那么epoll的效率就不如前两者了,毕竟回调通知的方式在大用户量下也会很慢。
旧版本linux内核和macOS等不支持epoll。