区别与联系

联系:他们三个都是在Linux上使用的I/O多路复用技术,与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

区别:

  • select
  1. 支持的文件描述符数量受限(1024)
  2. 每次调用select都会把fd集合从用户空间拷贝到内核空间
  3. select会把fd集合中所有的文件描述符都遍历一遍无论是否就绪
  • poll

解决了文件描述符数量的限制

  • epoll

解决了上述三个缺点

epoll的实现

增加文件描述符的数量

为了解决缺点一,epoll并没有将fd数量直接限定死而是将数量与系统内存想关联起来可以通过命令cat /proc/sys/fs/file-max查看支持的文件描述符数量。

只轮询就绪队列

select和poll方法当fd到一定数量的时候效率就会显著降低,究其原因,是因为他会轮询所有的文件描述符,有数据就处理没数据就跳过,而epoll只处理就绪的fd,它有一个就绪设备的队列,每次只轮询该队列的数据,然后进行处理

从用户空间到内核的拷贝

这个我也说不清,太菜了,请看文末链接中的epoll系列文章,相信一定会有所收获

epoll的工作方式

水平触发

LT(level triggered) 是默认/缺省的工作方式,同时支持 block和no_block socket。这种工作方式下,内核会通知你一个fd是否就绪,然后才可以对这个就绪的fd进行I/O操作。就算你没有任何操作,系统还是会继续提示fd已经就绪,不过这种工作方式出错会比较小,传统的select/poll就是这种工作方式的代表。

边沿出发

ET(edge-triggered) 是高速工作方式,仅支持no_block socket,这种工作方式下,当fd从未就绪变为就绪时,内核会通知fd已经就绪,并且内核认为你知道该fd已经就绪,不会再次通知了,除非因为某些操作导致fd就绪状态发生变化。如果一直不对这个fd进行I/O操作,导致fd变为未就绪时,内核同样不会发送更多的通知,因为only once。所以这种方式下,出错率比较高,需要增加一些检测程序。

https://idndx.com/2014/09/01/the-implementation-of-epoll-1/

总结

学习编程这么久,发现一遇到问题本质的东西,还是不要看中文博客的好。

最佳顺序应该是:

  1. 看源码
  2. 看官方文档
  3. 看国外大牛的博客(国内能把一件事讲清楚的人太少太少了,可能跟东西方思维方式不同的原因,总感觉老外讲的比较清晰易懂)