select的缺点:
单个进程能够监视的文件描述符的数量存在最大限制,通常是1024,当然可以更改数量,但由于select采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;(在linux内核头文件中,有这样的定义:#define __FD_SETSIZE 1024)
内核 / 用户空间内存拷贝问题,select需要复制大量的句柄数据结构,产生巨大的开销;
select返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件;
select的触发方式是水平触发,应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程。
poll:
优势:
1.无上限1024。
2.由于它不修改pollfd里的数据,所以它可以不用每次都填写了。
3.方便的知道远程的状态比如宕机
缺点:
1、还要轮巡
2、不能动态修改set。
其实大多数client不用考虑这个,除非p2p应用。一些server端用不用考虑这个问题。
大多时候他都比select更好。甚至如下场景比epoll还好:
你要跨平台,因为epoll只支持linux。
socket数目少于1000个。
大于1000但是是socket寿命比较短。
没有其他线程干扰的时候。
相比select模型,poll使用链表保存文件描述符,因此没有了监视文件数量的限制,但select三个缺点依然存在。
拿select模型为例,假设我们的服务器需要支持100万的并发连接,则在__FD_SETSIZE 为1024的情况下,则我们至少需要开辟1k个进程才能实现100万的并发连接。除了进程间上下文切换的时间消耗外,从内核/用户空间大量的无脑内存拷贝、数组轮询等,是系统难以承受的。因此,基于select模型的服务器程序,要达到10万级别的并发访问,是一个很难完成的任务。
epoll:
优点:
1.只返回触发的事件。少了拷贝消耗,迭代轮训消耗。
2.可以绑定更多上下文,不仅仅是socket。
3.任何时间处理socket。这些问题都是有内核来处理。了。这个还需要继续学习啊。
4.可以边缘触发。
5.多线程可以在同一个epoll wait里等待。
缺点:
1.读写状态变更之类的就要麻烦些,在poll里只要改一个bit就可以了。在这里面则需要改更多的位数。并且都是system call。
2.创建socket也需要两次系统调用,麻烦。
3.只有linux下可以使用
4.复杂难调试
适合场景
1.多线程,多连接。在单线程还不如poll
2.大量线程监控1000上,
3.相对长寿命的连接。系统调用会很耗时。
4.linux依赖的事情。