Linux|linux c++ select/poll/epoll 的个人见解

原理 Select
通过设置或者检查存放在数据结构 fd_set 中的标志位的来鉴别事件。Fd_set是一个输入输出参数,用户通过设置(FD_SET)相应的标志位标识关注的描述符,经内核拷贝到内核空间;内核根据输入fd_set 扫描对应的描述符,新建另一fd_set标识活跃的描述符,扫描完毕后将含有活跃描述符的fd_set 拷贝到用户空间。用户检查(FD_ISSET)内核输出的fd_set 确定活跃的描述符。(进程的fd的分配都是从3开始的,0、1、2已经用作标准输入,输出和错误?而fd_set的每一位对应一个fd。)
Poll
poll与select相似,poll用结构体标识一个fd,将关注的事件合并用events位标识。用户将关注的fd对应的结构体添加到数组中,并从用户空间拷贝到内核空间。内核轮询数组标识的fd,如有就绪fd这设置对应结构体的revents标志位,并继续遍历,最后将结构体数组拷贝到用户空间,用户检查revents标识并进行处理。如遍历完仍未有fd就绪,则挂起当前进程,直到再次被调度,被唤醒后再次遍历结构数组。采用“水平触发”的侦测方式,如检测到fd就绪后,没处理,那么下次epoll时会再次报告该fd。
Epoll
Epoll在用户空间和内核使用mmap方式传递数据(epoll_ctl函数添加关注的fd),避免了复制开销。Epoll使用就绪通知的模式,内核将就绪的fd添加到就绪队列中并返回,epoll_wait收到的都是就绪的fd。支持两种侦测方式,“边沿触发”和“边沿触发”,当采用“水平触发”(默认)的侦测方式,有poll相同的问题。
进程管理最大文件描述符 Select
由宏定义FD_SETSIZE决定,用一个unsigned long数组表示。一般FD_SETSIZE定义位1024,可以修改FD_SETSIZE来改变select管理描述符的数量。
Poll
基于链表存储,无上限,但受内存上限限制
Epoll
同poll。
效率 Select
内核和用户空间使用内核拷贝的方式交互数据,无论内核和用户空间,都需要轮询整个fd_set,当随管理的fd增加时,效率会呈线性下降。
【Linux|linux c++ select/poll/epoll 的个人见解】Poll
同select
Epoll
Epoll没有内核拷贝,而且只返回就绪的fd。在侦听大量不活跃的fd时,效率比较高。但在侦听少量活跃的fd时,性能不如前两者。因为epoll使用了复杂算法。

    推荐阅读