浅谈Linux epoll机制

epoll是Linux提供的一种高效I/O事件通知机制,它使用红黑树存储文件描述符并利用回调函数处理就绪事件,减少了用户态和内核态的转换及遍历开销。相比select和poll,epoll在大量文件描述符时表现出更好的性能,尤其在边缘触发模式下,仅监听一次事件,降低了CPU耗时。
摘要由CSDN通过智能技术生成

前言

概述

epoll是一种当文件描述符的内核缓冲区非空的时候,发出可读信号进行通知,当写缓冲区不满的时候,发出可写信号通知的机制;

关键函数

int epoll_create(int size);创建 eventpoll 对象,并将 eventpoll 对象放到 epfd 对应的 file->private_data 上,返回一个 epfd,即 eventpoll 句柄。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) //返回值:成功 0;失败 -1
对一个 epfd 进行操作。op 表示要执行的操作,包括 EPOLL_CTL_ADD (添加)、EPOLL_CTL_DEL (删除)、EPOLL_CTL_MOD (修改);fd 表示被监听的文件描述符;event 表示要被监听的事件,包括:

  • EPOLLIN(表示被监听的fd有可以读的数据)
  • EPOLLOUT(表示被监听的fd有可以写的数据)
  • EPOLLPRI(表示有可读的紧急数据)
  • EPOLLERR(对应的fd发生异常)
  • EPOLLHUP(对应的fd被挂断)
  • EPOLLET(设置EPOLL为边缘触发)
  • EPOLLONESHOT(只监听一次)

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) //返回值:监听到的产生的事件数
等待 epfd 监听的 fd 所产生对应的事件。epfd 表示 epoll句柄;events 表示回传处理事件的数组;maxevents 表示每次能处理的最大事件数;timeout:等待 IO 的超时时间,-1 表示一直阻塞直到来 IO 被唤醒,大于 0 表示阻塞指定的时间后被唤醒;

数据结构

epoll机制流程
epoll机制概述epoll使用红黑树去监听并维护所有文件描述符,调用epoll_create时,内核除了帮我们在epoll文件系统里创建file结点外,还会在内核里创建红黑树用于存储以后epoll_ctl传来的socket,同时还会创建一个list链表,用来存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表有没有数据即可,有数据就返回,没有数据就sleep,等到timeout时间到后即使链表中没有数据也返回

select、poll与epoll机制对比

  • cpu耗时对比
文件描述符数量poll() cpu timeselect() cpu timeepoll() cpu time
100.610.730.41
1002.930.42
100035350.53
100009909300.66
  • 用户态将文件描述符传入内核的方式

select:创建3个文件描述符集并拷贝到内核中,分别监听读、写、异常动作;这里受到单个进程可以打开的fd数量限制,默认是1024。

poll:将传入的struct pollfd结构体数组拷贝到内核中进行监听。

epoll:执行epoll_create会在内核的高速cache区中建立一颗红黑树以及就绪链表(该链表存储已经就绪的文件描述符)。接着用户执行的epoll_ctl函数添加文件描述符会在红黑树上增加相应的结点。

  • 内核态检测文件描述符读写状态的方式

select:采用轮询方式,遍历所有fd,最后返回一个描述符读写操作是否就绪的mask掩码,根据这个掩码给fd_set赋值。

poll:同样采用轮询方式,查询每个fd的状态,如果就绪则在等待队列中加入一项并继续遍历。

epoll:采用回调机制。在执行epoll_ctl的add操作时,不仅将文件描述符放到红黑树上,而且也注册了回调函数,内核在检测到某文件描述符可读/可写时会调用回调函数,该回调函数将文件描述符放在就绪链表中。

  • 找到就绪的文件描述符并传递给用户态的方式

select:将之前传入的fd_set拷贝传出到用户态并返回就绪的文件描述符总数。用户态并不知道是哪些文件描述符处于就绪态,需要遍历来判断。

poll:将之前传入的fd数组拷贝传出用户态并返回就绪的文件描述符总数。用户态并不知道是哪些文件描述符处于就绪态,需要遍历来判断。

epoll:epoll_wait只用观察就绪链表中有无数据即可,最后将链表的数据返回给数组并返回就绪的数量。内核将就绪的文件描述符放在传入的数组中,所以只用遍历依次处理即可。这里返回的文件描述符是通过mmap让内核和用户空间共享同一块内存实现传递的,减少了不必要的拷贝。

  • 重复监听的处理方式

select:将新的监听文件描述符集合拷贝传入内核中,继续以上步骤。

poll:将新的struct pollfd结构体数组拷贝传入内核中,继续以上步骤。

epoll:无需重新构建红黑树,直接沿用已存在的即可。

epoll高效的原因

  • 减少了用户态和内核态的文件句柄拷贝
    mmap加速了内核与用户空间的信息传递,epoll是通过内核与用户mmap同一块内存,避免了无谓的内存拷贝;

  • 减少了对可读可写文件句柄的遍历,IO性能不会随着监听的文件描述的数量增长而下降
    使用红黑树存储fd以及对应的回调函数,其插入、查找、删除性能都不错,相比于hash,不必预先分配很多的空间;

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值