selcet、epoll的实现机制以及epoll为什么高效?
程序员文章站
2022-05-12 11:27:08
...
IO多路复用模型通常有三种:poll、select、epoll
select一次事件处理的过程 : 需要两次拷贝和两次轮询(1次内核轮询、一次用户轮询)
- 从用户态拷贝 文件描述符数组 到内核态。(用户态->内核态的拷贝)
- 内核态需要遍历这个数组(轮询查看是否有事件准备就绪),如果有的话,会修改 拷贝到内核态的这个数组。(内核轮询)。
- 内核将就绪好的数组拷贝给用户。(内核态->用户态的拷贝)
- 因为内核已经将 数组中的数据修改了,所以用户又需要轮询一次,查看是哪些事件准备就绪了。(用户轮询)
- 下一次的话,用户又需要将文件描述符数组拷贝到内核态(因为内核中的那个数组已经被改了)。
因此一次事件处理的过程,需要两次拷贝和两次轮询,而如果下一次事件处理,仍需两次拷贝两次轮询。。
epoll一次需要最开始的一次拷贝,另一次内核到用户态的拷贝 数据量也不是很大;0次轮询。
- 内核创建一个红黑树节点,用来管理那些文件描述符。
- 用户将文件描述符数组 拷贝到内核空间,内核将文件描述符挂在树上。(用户态->内核态的拷贝)
- 内核使用回调机制,等事件准备就绪,返回给内核,内核将这些就绪事件添加到就绪链表中。(内核回调)
- 内核将就绪链表返回给用户,用户直接对就绪链表处理即可,不需轮询。
- 下次也并不需要将文件描述符数组拷贝到内核态,因为内核空间里有个红黑树节点在管理文件描述符。
epoll过程
epoll机制提供了三个系统调用epoll_create、epoll_ctl、epoll_wait
下面是这三个函数的原型
- epoll_create
int epoll_create(int size);
此函数返回一个epoll的文件描述符
- epoll_ctl
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
此函数是添加、删除、修改事件
epfd:epoll的文件描述符
op:表示选项,EPOLL_CTL_ADD(添加事件)、EPOLL_CTL_MOD(修改事件)、EPOLL_CTL_DEL(删除事件)
fd:要操作的文件描述符
event:事件信息
- epoll_wait
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
此函数是等待条件满足,放回值为准备就绪的事件数
epfd:epoll的文件描述符
events:返回的事件信息
maxevents:要等待的最大事件数
timeout:超时时间
- epoll_event
struct epoll_event
{
uint32_t events; //epoll事件
epoll_data_t data; //联合体,一般表示文件描述符
};
参考链接:
https://blog.csdn.net/weixin_42462202/article/details/95315926
https://blog.csdn.net/weixin_42462202/article/details/95377075