网络编程实战
盛延敏
前大众点评云平台首席架构师
立即订阅
6034 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 学好网络编程,需要掌握哪些核心问题?
免费
第一模块:基础篇 (9讲)
01 | 追古溯源:TCP/IP和Linux是如何改变世界的?
02 | 网络编程模型:认识客户端-服务器网络模型的基本概念
03丨套接字和地址:像电话和电话号码一样理解它们
04 | TCP三次握手:怎么使用套接字格式建立连接?
05 | 使用套接字进行读写:开始交流吧
06 | 嗨,别忘了UDP这个小兄弟
07 | What? 还有本地套接字?
08 | 工欲善其事必先利其器:学会使用各种工具
09丨答疑篇:学习网络编程前,需要准备哪些东西?
第二模块:提高篇 (10讲)
10 | TIME_WAIT:隐藏在细节下的魔鬼
11 | 优雅地关闭还是粗暴地关闭 ?
12 | 连接无效:使用Keep-Alive还是应用心跳来检测?
13 | 小数据包应对之策:理解TCP协议中的动态数据传输
14丨UDP也可以是“已连接”?
15 | 怎么老是出现“地址已经被使用”?
16 | 如何理解TCP的“流”?
17 | TCP并不总是“可靠”的?
18 | 防人之心不可无:检查数据的有效性
19丨提高篇答疑:如何理解TCP四次挥手?
期中复习周 (2讲)
期中大作业丨动手编写一个自己的程序吧!
免费
期中大作业丨题目以及解答剖析
免费
第三模块:性能篇 (12讲)
20 | 大名⿍⿍的select:看我如何同时感知多个I/O事件
21 | poll:另一种I/O多路复用
22 | 非阻塞I/O:提升性能的加速器
23 | Linux利器:epoll的前世今生
24 | C10K问题:高并发模型设计
25 | 使用阻塞I/O和进程模型:最传统的方式
26 | 使用阻塞I/O和线程模型:换一种轻量的方式
27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件
28 | I/O多路复用进阶:子线程使用poll处理连接I/O事件
29 | 渐入佳境:使用epoll和多线程模型
30 | 真正的大杀器:异步I/O探索
31丨性能篇答疑:epoll源码深度剖析
第四模块:实战篇 (4讲)
32 | 自己动手写高性能HTTP服务器(一):设计和思路
33 | 自己动手写高性能HTTP服务器(二):I/O模型和多线程模型实现
34 | 自己动手写高性能HTTP服务器(三):TCP字节流处理和HTTP协议实现
35 | 答疑:编写高性能网络编程框架时,都需要注意哪些问题?
结束语 (1讲)
结束语丨我相信这不是结束,让我们江湖再见
网络编程实战
登录|注册

23 | Linux利器:epoll的前世今生

盛延敏 2019-09-30
你好,我是盛延敏,这里是网络编程实战第 23 讲,欢迎回来。
性能篇的前三讲,非阻塞 I/O 加上 I/O 多路复用,已经渐渐帮助我们在高性能网络编程这个领域搭建了初步的基石。但是,离最终的目标还差那么一点,如果说 I/O 多路复用帮我们打开了高性能网络编程的窗口,那么今天的主题——epoll,将为我们增添足够的动力。
我在文稿中放置了一张图,这张图来自 The Linux Programming Interface(No Starch Press)。这张图直观地为我们展示了 select、poll、epoll 几种不同的 I/O 复用技术在面对不同文件描述符大小时的表现差异。
从图中可以明显地看到,epoll 的性能是最好的,即使在多达 10000 个文件描述的情况下,其性能的下降和有 10 个文件描述符的情况相比,差别也不是很大。而随着文件描述符的增大,常规的 select 和 poll 方法性能逐渐变得很差。
那么,epoll 究竟使用了什么样的“魔法”,取得了如此令人惊讶的效果呢?接下来,我们就来一起分析一下。

epoll 的用法

在分析对比 epoll、poll 和 select 几种技术之前,我们先看一下怎么使用 epoll 来完成一个服务器程序,具体的原理我将在 29 讲中进行讲解。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(23)

  • yusuf
    之前对epoll01.c中第66行while(1)很困惑,不明白是从哪里跳出这个循环的。后来通过gdb调试分析,发现在55行把socket_fd设置为了非阻塞,然后在68行调用read时,socket_fd没有数据可读会直接返回-1(errno = EAGAIN),从而在73行通过break跳出了while(1)循环。希望对同样有此困惑的同学有所帮助。

    作者回复: gdb都用上了,牛~

    2019-10-21
    3
  • 传说中的成大大
    我回想和对了poll和epoll的代码 觉得效率问题主要出现在 epoll返回的是有事件发生的数组,而poll返回的是准备好的个数,每次poll函数返回都要遍历注册的描述符结合数组 尤其是数量越大遍历次数就越多 我觉得性能差异在这里 抛开阻塞和阻塞i/o层面

    作者回复: 这是一个很重要的点,恭喜你悟到了 :)

    2019-10-08
    3
  • 刘丹
    提个小建议,能否把代码解说(例如:第 41-46 行判断了各种错误情况)作为注释放在代码里?

    作者回复: 这里主要是因为播报员无法通读代码,所以把代码解说拿出来了。

    2019-09-30
    2
  • 西兹兹
    边缘触发不是很理解,只通知第一次,如果报文没读完,后续的数据怎么办?

    作者回复: 你的程序要接着把它读完,否则就会没完没了的收到可读事件。

    2019-11-06
    1
    1
  • 贺荣伟
    老师,您好,在总结里:“避免了用户态 - 内核态频繁的数据拷贝”这句话是什么意思的呢?文稿中好像没有提到 epoll 的数据拷贝?频繁指的是什么呢?另外,对比之前的 ,select,poll,epoll 三者在数据拷贝之间的区别又有什么不同呢?希望老师回答一下,谢谢!

    作者回复: 在后面的章节里对select、poll、epoll这几个技术进行了不同程度的比较,你可以接着往下读。

    2019-10-24
    1
    1
  • CCC
    试了一下select和poll都是条件触发的,发现套接字是readable了只要没被read就会一直报这个套接字可读,而epoll在边缘模式下只会在第一次报套接字可读,可能这也是epoll为什么效率高的缘故吧,因为不用盯着套接字一直报。
    2019-10-06
    1
  • 空想家
    LT + non-blocking 和 ET + non-blocking 有什么区别吗?性能谁更好一点?

    epoll 的惊群问题会讲吗?

    作者回复: LT和ET的区别在文稿里已经给出了。

    我理解的惊群问题是当一个网络套接字上有事件发生时,多个线程或者进程会感知,从而引发一群线程干活。

    我认为设计良好的程序应该避免这样的问题,比如一个套接字只被一个线程所管理。我们后面的框架设计也是遵循了这个原则。

    2019-09-30
    1
  • godtrue
    期待后面分享 select/poll/epoll三者产生,随着处理的文件描述符越多性能差异越大的原因?

    看文章内容和评论,目前的依据有三个
    1:避免了用户态-内核态频繁的数据拷贝,这个老师会在后面讲,猜测是零拷贝技术
    2:边缘条件触发比条件触发性能更优,select/poll都是条件触发,这个老师在评论中又讲有人测试过,其实他俩性能之差,并不如理论上讲的那么大,这需要测试下
    3:从poll和epoll的返回值角度来思考,epoll返回的是有事件发生的数组,poll返回的是事件就绪的个数,每次poll返回都需要遍历注册的文件描述符的结果数组,尤其数据量越大遍历次数就越多,这个也是poll相对于epoll慢的原因
    2019-11-24
  • 林林
    epoll 通过改进的接口设计,避免了用户态 - 内核态频繁的数据拷贝,大大提高了系统性能。
    请问避免用户态和内核态之间的频繁数据拷贝,从哪能体现出来?

    作者回复: 从内核实现上能体现出来,你可以看下后面的源码解读部分。

    2019-11-22
  • HunterYuan
    老师给的例子,是不是把close(efd),给掉了?还是不用关闭

    作者回复: 应该是忘记关了 :)

    2019-11-20
  • Steiner
    这个注册过的fd好像删不删都无所谓啊

    作者回复: 需要删除掉,否则fd不能复用了。

    2019-11-07
  • 贺荣伟
    EPOLL_CLOEXEC 标志与 open 调用时的 O_CLOEXEC 标志类似 ,即进程被替换时会关闭打开的文件描述符。
    2019-10-24
    1
  • Steiner
    请问如果我用epoll_ctl显式更改event事件,那么epoll_wait会不会检测到,并装载到events数组中?

    作者回复: 当然会,自动更新,动态检测,这就是NB的地方啊。

    2019-10-23
  • yusuf
    https://github.com/linuxxiaoyu/block
    执行后都会重复打印”need read socket_fd“和“poll need to read”,所以select和poll应该都是条件触发

    作者回复: 就喜欢你这样努力完成作业,实际写代码的样子。赞赞赞。

    2019-10-21
  • moob
    边缘触发的情况, 如果epoll_wait时提供的events数组太小,那么会错过事件?

    作者回复: 如果你读了后面答疑部分的源码就会明白,答案是否定的。如果你设置一个很小的events数组,会影响事件的时效性,也就是说,可能10秒前的一个I/O事件,现在你才收到,但是不会错过事件,其原因是事件总在内核中记录着。你不收,内核里也有;你收的快一点,时效性就越好,表现出对用户的体验就越好。

    2019-10-15
  • 小蚂蚁
    老师您好能详细讲下select,poll,epoll底层实现原理和差别吗?为什么opoll的性能会大幅优于select和poll呢?能在答疑篇中系统讲下吗?谢谢。

    作者回复: 第29讲里讲到了,答疑篇更是从源码角度深度剖析了,希望可以解答你的疑惑。

    2019-10-14
  • 刘丹
    代码里的2个continue关键词好像都是可以删除的?

    作者回复: 可以删除。

    2019-10-04
  • 张立华
    请问下老师,一个epoll队列里有100万个socket,性能怎么样,有没试过

    作者回复: 我没有试过,你可以试下哈。

    2019-10-03
  • 向东
    为何在水平触发的epoll03,当tcpclient都退出了,还说有数据可读呢,get event on socket fd ==5,二是请问为何每次都从五开始呢,前面0-5分别是谁占用了呢,谢谢。

    作者回复: 因为这部分数据没有被处理掉,而这个正是条件触发的精髓。

    至于描述字,我是这么理解的,0,1,2分别被stdin, stdout和stderr所用,3被监听套接字所用,本地连接的客户端描述字是4,那么本地已连接套接字就是5了。

    2019-10-03
  • 沉淀的梦想
    文中提到“如果 epoll_create1() 的输入 size 大小为 0,则和 epoll_create() 一样,内核自动忽略。”,epoll_create1的输入参数不是flags吗?size又是指什么?

    作者回复: 这里是笔误,应该是epoll_create1的输入参数flags如为0,则和epoll_create()一样。

    已经让编辑勘误了,感谢指出。

    2019-10-01
收起评论
23
返回
顶部