31丨性能篇答疑:epoll源码深度剖析
该思维导图由 AI 生成,仅供参考
基本数据结构
- 深入了解
- 翻译
- 解释
- 总结
本文深度剖析了Linux下高性能网络编程中的关键技术——epoll的源码实现。通过对epoll_create、epoll_ctl等关键函数的分析,揭示了epoll如何高效地管理文件描述字和事件,以及内核中事件回调的原理。文章还从实现角度比较了epoll与poll/select的效率差异,指出epoll通过红黑树和就绪事件列表的维护,避免了大量内存申请和释放的操作,大大提高了性能。通过对比poll/select的实现,突显了epoll克服了poll/select的弊端,成为Linux下高性能网络编程的皇冠。总体而言,本文为读者提供了深入理解Linux下高性能网络编程中epoll技术的重要参考,对于从事网络编程或对Linux内核感兴趣的技术人员具有较高的参考价值。
《网络编程实战》,新⼈⾸单¥59
全部留言(18)
- 最新
- 精选
- herongwei这篇文章写得非常棒!之前学 epoll,只会流于表面,也很少去深度剖析底层的数据结构,多读几遍! 另外分享一个大佬同学 epoll 内核源码详解发的帖子:https://www.nowcoder.com/discuss/26226
作者回复: 赞分享。
2019-10-26222 - 鱼向北游select这种是把等待队列和就绪队列混在一起,epoll根据这两种队列的特性用两种数据结构把这两个队列分开,果然在程序世界没有解决不了的事情,如果有,就加一个中间层
作者回复: 你这个理解倒是比较有趣,程序是伟大的。
2019-10-1819 - HerofH首先感谢老师的精彩分析。 然后说下我的个人理解:epoll之所以效率比select高,原因在于select要做的事情太多,每次调用select不仅需要将描述符集添加到监听队列中,还要负责监听事件发生后的处理,以及select最后的清理工作等等... 而epoll则把这么多事情分到了epoll_ctl和epoll_wait去处理,调用epoll_ctl可以开启事件的监听工作,epoll_wait则可以完成对已激活的事件的处理工作,最后close(epfd)完成epoll的清理工作。 而select和epoll_wait是循环中反复调用的,epoll_wait做的事情比select少多了,因此从这个角度来说epoll效率会比select效率高。 除此之外,个人感觉epoll还有一个妙处就是就绪链表,当监听的事件发生后,相应的epitem会自动在监听回调中将其添加到就绪链表中,而对于select来说,则需要不停对所有监听的描述符进行遍历,来检查它们的状态。 不知道理解是否正确,敬请指正。
作者回复: 👍
2020-01-159 - 凉人。感觉这一章是最难以理解,如果多一些结构图,流程图,会好很多。
作者回复: 嗯,好建议,记下了。
2020-02-118 - fackgc17可以提供一下分析用的 kernel 版本吗
作者回复: linux 4.14.4
2019-10-264 - heyman请问一下,为什么要用红黑树?是因为要排序吗?排序的意义又在哪里?确保查找、插入和删除的高效还不够吗?
作者回复: 就是要确保查找、插入和删除的高效啊,要知道,10K以上的连接时,这个对性能要求非常苛刻,一个高效的数据结构对于完成上述操作是非常关键的。
2020-04-1843 - 瓜牛还是没明白为啥epoll有红黑树之后就不用在用户空间和内核空间之间拷贝了,或者说poll/select为啥要在用户空间和内核空间之间拷贝?
作者回复: 简单的说,poll/select需要每次循环判断出有事件的fd,这份信息是一个全量的拷贝;而epoll则直接拿到事件发生后的信息。一个是ALL,一个是局部变化的部分,你说少没少拷贝?
2021-11-052 - 钱功力不够,读起来有些费劲,好似拿到了九阴真经,不过需要黄姑娘翻译一下! 如果能来个图,就好了😁
作者回复: 待我找黄姑娘来:)
2019-12-012 - xupeng1644老师 在Level-triggered VS Edge-triggered小节中给出了Level-triggered的实现机制,可以再给下Edge-triggered的吗
作者回复: Edge-triggered不需要特殊处理,就是有事件通知一次结束,这里Level-triggered还需要把没有完结的事件在拷贝一次通知给应用程序,所以需要特殊处理下。
2020-02-281 - J.M.Liu老师,我请教两个问题: 1.ep_send_events_proc这个函数在把events列表拷贝到用户空间前会调用ep_item_poll函数,已确定对应的fd上的事件依旧有效。那ep_item_poll是根据什么来确定事件的有效性呢? 2.在ep_send_events_proc处理level-triggered的时候,有这么一段话“At this point, no one can insert into ep->rdllist besides us. The epoll_ctl() callers are locked out by ep_scan_ready_list() holding "mtx" and the poll callback will queue them in ep->ovflist.”意思是说epoll_ctl()的调用者也被锁在外面了。这个锁是说在ep_send_events_proc还没处理完的时候,epoll_ctl()无法操纵rdllist,但是之后是可以的,以实现再次注册感兴趣的时间。是这样吗?
作者回复: 看得好自信,汗,我试着回答哈: 1.根据套接字文件上的poll接口,套接字文件上记录了它有效的事件: static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt) { pt->_key = epi->event.events; return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->event.events; } 2.是的。 static int ep_scan_ready_list(struct eventpoll *ep, int (*sproc)(struct eventpoll *, struct list_head *, void *), void *priv, int depth, bool ep_locked) { int error, pwake = 0; unsigned long flags; struct epitem *epi, *nepi; LIST_HEAD(txlist); /* * We need to lock this because we could be hit by * eventpoll_release_file() and epoll_ctl(). */ if (!ep_locked) mutex_lock_nested(&ep->mtx, depth); ... }
2019-10-291