##select模型
- 最大并发数限制,因为一个进程所打开的FD(文件描述符)是有限制的,由FD_SETSIZE设置,默认值是1024/2048,因此Select模型的最大并发数就被相应限制了。自己改改这个FD_SETSIZE?想法虽好,可是先看看下面吧…
- 效率问题,select每次调用都会线性扫描全部的FD集合,这样效率就会呈现线性下降,把FD_SETSIZE改大的后果就是,大家都慢慢来,什么?都超时了??!!
- 内核/用户空间 内存拷贝问题,如何让内核把FD消息通知给用户空间呢?在这个问题上select采取了内存拷贝方法。
##poll模型
基本上效率和select是相同的,select缺点的2和3它都没有改掉。
##Epoll的提升
把其他模型逐个批判了一下,再来看看Epoll的改进之处吧,其实把select的缺点反过来那就是Epoll的优点了。
- Epoll没有最大并发连接的限制,上限是最大可以打开文件的数目,这个数字一般远大于2048, 一般来说这个数目和系统内存关系很大,具体数目可以cat /proc/sys/fs/file-max察看。
- 效率提升,Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。
- 内存拷贝,Epoll在这点上使用了“共享内存”,这个内存拷贝也省略了。
##总结
select 是采用内核轮询方式,每次调用都需要轮询 FD_SET,默认最多可以接受 1024 个fd,可更改为更大,但是随着数量的增多,轮询周期的变长,性能会急剧下降;
poll 是 select 的改进版,将 FD_SET 改造成由( fd,监听事件类型,实际事件类型 )为节点组成的链,解除了1024 的限制,其他并无大的区别,当 fd 多时,同样会造成效率下降;
epoll 将 轮询机制 改造为 事件触发机制,给每一个 fd 附上一个 callback,当监听事件发生时,就将 fd 链接到 就绪链表,调用 epoll_wait 时,只用检查就绪链表就可以了,而不需要像 select 和 poll 一样进行轮询。
另外,select 和 poll 是将存有 fd 的结构或者数组再每次调用的时候都复制到内核态,然后调用完再复制回用户态,而无所谓是否有意义。epoll 使用内存映射,减去了这部分的data-copy操作。
再者,从触发方式上来看,select 和 poll 都只有 条件触发(也可以叫水平触发),epoll 则有条件触发 和 事件触发(也可以叫边缘触发)两种。
在选择使用哪种方式的时候,需要根据 fd 的多少和活跃程度来判断。当fd 数量较少,且都比较活跃的时候,使用 select 或者 poll 反而有可能效率更高,因为毕竟 epoll 要有多次的回调函数。
好东西都是要付出代价的!