27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件
该思维导图由 AI 生成,仅供参考
重温事件驱动
基于事件的程序设计: GUI、Web
- 深入了解
- 翻译
- 解释
- 总结
本文介绍了如何使用I/O多路复用技术结合单线程处理所有I/O事件。作者首先回顾了基于事件驱动的程序设计思想,比如GUI和Web编程中的事件处理机制。然后对比了使用fork、pthread和单reactor线程等不同的I/O模型和线程模型设计,指出它们在处理多并发网络编程中的局限性。接着,作者详细介绍了使用poll单线程处理所有I/O事件的设计思路,并给出了相应的样例程序。该样例程序展示了如何使用event_loop、acceptor和tcp_server等组件来实现单线程处理I/O事件的网络编程框架,并提供了相应的回调函数来处理连接建立、数据读取、数据发送和连接关闭等操作。通过这种设计,可以有效地提高程序的性能和并发处理能力,满足高性能、高并发的需求。整体而言,本文通过实例和技术原理的介绍,为读者提供了一种高效的网络编程解决方案,有助于读者快速了解并应用于实际开发中。文章还提出了两道思考题,鼓励读者深入思考并分享交流。
《网络编程实战》,新⼈⾸单¥59
全部留言(43)
- 最新
- 精选
- 林林worker thread 和 reactor thread之间怎么进行数据传递?是要利用队列+锁吗?
作者回复: 这就是两个普通的producer-consumer线程关系,使用队列+锁的方式是一个比较常见的实现方式。
2019-11-2615 - 钱1:事件驱动模型的设计思想是啥? 事件驱动模型的设计的思想是,一个无限循环的事件分发线程在后台运行,一旦做了某种操作触发了一个事件,这个事件就会被放置到事件队列中,事件分发线程的任务,就为这个发生的事件找到对应的事件回调函数并执行它。 这里有个疑问,事件分发线程怎么找到事件的回调函数,并调用它的? 2:事件驱动模型的优势是啥? 事件驱动的好处是占用资源少,效率高,可扩展性强,是支持高性能高并发的不二之选。 老师好,请问占用资源少这个结论是怎么得出来的? 3:IO网络通信是怎么实现事件驱动模型的? 通过使用 poll、epoll 等 I/O 分发技术,可以设计出基于套接字的事件驱动程序,从而满足高性能、高并发的需求。 4:Reactor模型是啥玩意? Reactor模型(中文叫做反应堆模型)也就是事件驱动模型或者是 Event loop 模型。 这个模型的核心有两点。 第一,它存在一个无限循环的事件分发线程,或者叫做 reactor 线程、Event loop 线程。这个事件分发线程的背后,就是 poll、epoll 等 I/O 分发技术的使用。 第二,所有的 I/O 操作都可以抽象成事件,每个事件必须有回调函数来处理。acceptor 上有连接建立成功、已连接套接字上发送缓冲区空出可以写、通信管道 pipe 上有数据可以读,这些都是一个个事件,通过事件分发,这些事件都可以一一被检测,并调用对应的回调函数加以处理。 5:Reactor模型——解决了空闲连接占用资源的问题,Reactor线程只负责处理 I/O 相关的工作,业务逻辑相关的工作都被裁剪成一个一个的小任务,放到线程池里由空闲的线程来执行。当结果完成后,再交给反应堆线程,由Reactor线程通过套接字将结果发送出去。 所以,这个模式性能更优。 6:阻塞IO+多进程——实现简单,性能一般 7:阻塞IO+多线程——相比于阻塞IO+多进程,减少了上下文切换所带来的开销,性能有所提高。 8:阻塞IO+线程池——相比于阻塞IO+多线程,减少了线程频繁创建和销毁的开销,性能有了进一步的提高。 9:Reactor+线程池——相比于阻塞IO+线程池,采用了更加先进的事件驱动设计思想,资源占用少、效率高、扩展性强,是支持高性能高并发场景的利器。
作者回复: 第一个问题,回调函数和套接字对应的,通过套接字找到对应的回调函数; 第二个问题,因为是事件驱动,不需要分配固定的资源,仅仅使用几个线程就可以支持上万的连接,每个线程的利用率得到了最大提升。
2019-11-24412 - fxzhang老师可否讲解linux下如何开发的,最近想换工作,但是之前都在windows下面开发,想自学一下linux下是如何开发的,但是有一种找不到开头不知道该怎么学习的感觉,很无力
作者回复: 先学习一下Linux下的安装、配置、管理,把工作环境放到Linux下面,让Linux成为你的工作效率机器; 其次,慢慢学习Bash,感受一下Linux的能力; 接下来就是学习一些 Linux下的程序设计,如I/O、网络等。 如果你能把这篇系列的所有代码都改一遍,运行一遍,就是一个良好的开头。 加油~
2019-10-0910 - 刘忽悠没太理解epoll反应堆模型,和直接eopll的区别是什么? 不知道我这么理解对不对,一般使用epoll,假如新连接建立,注册cfd读事件,当事件触发,接着在主线程里面读出来,然后处理,接着发送;epoll反应堆模式是不是仅仅只是在注册事件的时候加了一个对应的回调函数,当事件触发,然后调用回调去处理?相当于统一了一下接口? 对于老师说的reactor+threadpool不知道理解的对不对,我个人理解是,当有新连接建立,因为监听描述符注册的是acceptor事件,这时候这个事件触发,触发之后注册新的描述符cfd的read事件,当cfd的读事件触发,这时候在reactor线程(主线程)里面调当初注册的回调函数来处理读事件,读出来之后,然后注销cfd的读事件,这时候把读出来的内容封装成Task,放到线程池的Task队列,通知线程池的工作线程——有任务了,唤醒一个线程对任务进行处理,处理完成之后,这时候注册cfd的写事件,然后work线程处理完成,一般情况下写缓冲区都是可以写,所以这时候在reactor线程里面,cfd的写事件被触发,这时候在reactor线程里面调用对应的回调函数把数据发送过去,接着然后注销写事件,注册读事件,继续监听客户端请求。这样一来,业务逻辑都在线程池里面去做,然后读,写都是通过在主线程,也就是reactor线程里面调用对应的回调函数来完成。 不知道这么理解reactor模式+线程池对不对?
作者回复: 基本是正确的。有一个小小的地方和我的理解不一致,就是对socket的读写,也是可以放到线程池里独立的线程去做,而主reactor线程就是一个事件分发器,不负责I/O操作,因为主reactor线程是一个非常重要的"大脑",尽量不要让它成为瓶颈。
2020-07-0135 - heymanreactor 线程无限循环,有点像轮询,效率不会很低吗?
作者回复: 不会。这里不是轮询哦,轮询是消耗cpu时间的,这里是系统提供的事件驱动,看似在无限循环,其实这个时候cpu被调度干其他事了,当真正有事件发生,cpu又会被切换回来,所以效率很高。
2020-04-185 - 传说中的成大大第一遍看完这篇文章 我就感受颇深 尤其是事件触发 这个模式 然后就想到工作当中的用到的skynet框架底层就是采用事件驱动,某个服务有数据达到 就去触发对应的服务,然后再回想工作当中很多逻辑都抽象成事件,通过一个主循环检测时间然后来触发对应的事件! 更重要的一点,专栏下的代码我全部是自己手动实现了一遍 还用上了gdb很开心 很满足 第27讲和第24讲 应该重点学习,这两讲都是很重要的理论基础
作者回复: 你是问题最多的,我想也是收获最大的。 调试、调试、调试,重要的问题讲三遍 :)
2019-10-155 - CPPC语言要是没两把刷子,买了也是浪费钱。再调试也得建立再看懂的基础上......
作者回复: C语言应该是大学期间必修课程吧.......
2020-08-103 - herongwei这篇文章,多了很多生动的图片,感觉干货满满啊,哈哈,希望后面的课程,也能多加点对应的图片就更好了。
作者回复: 我想应该是可以满足你的要求的:)
2019-10-242 - supermouse思考题第一道:https://github.com/YoungYo/yolanda/blob/master/chap-27/poll-server-onethread-homework.c 这是修改后的代码 思考题第二道: onMessage 方法就是处理 decode-compute-encode 逻辑的吧?
作者回复: 是的。
2020-02-251 - 阿卡牛使用多线程有线程池,使用多进程有进程池吗?
作者回复: 没有。
2019-11-1921