然而大多数应用场景中,需要监视的,socket相对固定,并不需要每次都修改。
epoll的优化措施
- 功能分离:进程到等待队列,进程阻塞
- 引入了就绪列表rdlist
epoll的优化措施一:功能分离
select低效的原因之一是将“维护等待队列”和“阻塞进程”两个步骤合二为一
大多数应用场景中,需要监视的socket相对固定,并不需要每次都修改。
:::tips
epoll将这两个操作分开,先用epoll_ctl维护等待队列,再调用epoll_wait阻塞进程。
:::
显而易见的,效率就能得到提升。
epoll的优化措施二:就绪列表rdlist
select低效的另一个原因在于程序不知道哪些socket收到数据,只能一个个遍历。
如果内核维护一个“就绪列表” rdlist,引用收到数据的socket 就能避免遍历。
:::tips
rdlist存储有事件发生的连接
:::
当socket接收到数据,中断程序做两个工作:
- 一方面修改rdlist
- 另一方面唤醒eventpoll 等待队列中的进程,进程A再次进入运行状态。
也因为rdlist 的存在,进程A可以知道哪些socket发生了变化。
epoll三大步骤
Epoll第一步epoll_create创建
当某个进程调用epoll_create方法时, 内核会创建一个eventpoll对象 (epfd文件描述符),和socket一样,它也会有等待队列。
Epoll第二步epoll_ctl注册
- 可以用epoll_ctl添加或刪除所监听的socket。
- 如果通过epoll_ctl添加sock1、sock2和sock3的监视,内核会将eventpoll添加到这三个socket的等待队列中
当socket收到数据后,中断程序会操作eventpoll的就绪队列rdlist,而不是直接操作读取数据的进程(如果进行A)。当sock2和sock3收到数据后,中断程序让这两个socket进入rdlist。
Epoll第三 步epoll_wait阻塞
当程序执行到epoll_wait时, 如果rdlist非空则返回, 如果rdlist为空,阻塞进程.
当socket接收到数据,中断程序一方面将其插入rdlist, 另一方面唤醒eventpoll等待队列 中的进程,进程A再次进入内核的工作队列。进程A进行运行状态。
正是因为epoll采用了红黑树的结构,所以能够监听的连接数,可以远远大于1024个