b站视频:BV1qJ411w7du
b站笔记:https://www.processon.com/view/link/5f36856b5653bb06f2ce529f
背景问题:网络服务器支持多个客户端连接。
原先解决办法:多线程。每个线程去处理一个请求。
select
poll
epoll
对比 | select | poll | epoll |
调用函数 | 一个函数 | 一个函数 | 一组函数 |
文件描述符数量 | select通过线性表描述文件描述符集合,文件描述符有上限,一般是1024,但可以修改源码,重新编译内核,不推荐 | poll是链表描述,突破了文件描述符上限,最大可以打开文件的数目 | epoll通过红黑树描述,最大可以打开文件的数目,可以通过命令ulimit -n number修改,仅对当前终端有效 |
将文件描述符从用户传给内核 | select和poll通过将所有文件描述符拷贝到内核态,每次调用都需要拷贝 | select和poll通过将所有文件描述符拷贝到内核态,每次调用都需要拷贝 | epoll通过epoll_create建立一棵红黑树,通过epoll_ctl将要监听的文件描述符注册到红黑树上 |
内核判断就绪的文件描述符 | select和poll通过遍历文件描述符集合,判断哪个文件描述符上有事件发生 | select和poll通过遍历文件描述符集合,判断哪个文件描述符上有事件发生 | epoll_create时,内核除了帮我们在epoll文件系统里建了个红黑树用于存储以后epoll_ctl传来的fd外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。 epoll是根据每个fd上面的回调函数(中断函数)判断,只有发生了事件的socket才会主动的去调用 callback函数,其他空闲状态socket则不会,若是就绪事件,插入list |
应用程序索引就绪文件描述符 | select/poll只返回发生了事件的文件描述符的个数,若知道是哪个发生了事件,同样需要遍历 | select/poll只返回发生了事件的文件描述符的个数,若知道是哪个发生了事件,同样需要遍历 | epoll返回的发生了事件的个数和结构体数组,结构体包含socket的信息,因此直接处理返回的数组即可 |
工作模式 | select和poll都只能工作在相对低效的LT模式下 | select和poll都只能工作在相对低效的LT模式下 | epoll则可以工作在ET高效模式,并且epoll还支持EPOLLONESHOT事件,该事件能进一步减少可读、可写和异常事件被触发的次数。 |
应用场景 | 当监测的fd数目较小,且各个fd都比较活跃,建议使用select或者poll 当所有的fd都是活跃连接,使用epoll,需要建立文件系统,红黑书和链表对于此来说,效率反而不高,不如selece和poll | 当监测的fd数目较小,且各个fd都比较活跃,建议使用select或者poll 当所有的fd都是活跃连接,使用epoll,需要建立文件系统,红黑书和链表对于此来说,效率反而不高,不如selece和poll | 当监测的fd数目非常大,成千上万,且单位时间只有其中的一部分fd处于就绪状态,这个时候使用epoll能够明显提升性能 |