Reactor 模式
也可以叫反应器模式或者应答者模式
reactor 模式简介
让我们先了解一下阻塞 I/O 与非阻塞 I/O
I/O 是非常缓慢的
I/O 绝对是计算机操作中最慢的. 访问 RAM 的事件为 ns 级别, 而访问磁盘或网络上的数据是 ms 级别的.
阻塞 I/O 与非阻塞 I/O
阻塞 I/O 的意思是, 一个 I/O 相关的请求发送过来, 相对应的函数调用, 将阻塞的线程执行, 直到操作完成
非阻塞 I/O 的意思是, 一个 I/O 请求, 系统收到后立即返回, 然后系统会主动有一个轮询, 当 I/O 请求完毕时, 开始执行 I/O 相关的函数调用.
接下来我用一个经典的例子来描述这两种 I/O 的区别
以一个餐饮为例, 每一个人来就餐就是一个事件, 他会先看一下菜单, 然后点餐. 就像一个网站会有很多的请求, 要求服务器做一些事情. 处理这些就餐事件的就需要我们的服务人员了.
在多线程处理的方式会是这样的:
一个人来就餐, 一个服务员去服务, 然后客人会看菜单, 点菜. 服务员将菜单给后厨.
二个人来就餐, 二个服务员去服务......
五个人来就餐, 五个服务员去服务......
这个就是多线程的处理方式, 一个事件到来, 就会有一个线程服务. 很显然这种方式在人少的情况下会有很好的用户体验, 每个客人都感觉自己是 VIP, 专人服务的. 如果餐厅一直这样同一时间最多来 5 个客人, 这家餐厅是可以很好的服务下去的.
来了一个好消息, 因为这家店的服务好, 吃饭的人多了起来. 同一时间会来 10 个客人, 老板很开心, 但是只有 5 个服务员, 这样就不能一对一服务了, 有些客人就要没有人管了. 老板就又请了 5 个服务员, 现在好了, 又能每个人都受 VIP 待遇了.
越来越多的人对这家餐厅满意, 客源又多了, 同时来吃饭的人到了 20 人, 老板高兴不起来了, 再请服务员吧, 占地方不说, 还要开工钱, 再请人就攒不到钱了. 怎么办呢? 老板想了想, 10 个服务员对付 20 个客人也是能对付过来的, 服务员勤快点就好了, 伺候完一个客人马上伺候另外一个, 还是来得及的. 综合考虑了一下, 老板决定就使用 10 个服务人员的线程池啦~~~
但是这样有一个比较严重的缺点就是, 如果正在接受服务员服务的客人点菜很慢, 其他的客人可能就要等好长时间了. 有些火爆脾气的客人可能就等不了走人了.
而非阻塞 I/O 会选择这样做:
老板后来发现, 客人点菜比较慢, 大部服务员都在等着客人点菜, 其实干的活不是太多. 老板能当老板当然有点不一样的地方, 终于发现了一个新的方法, 那就是: 当客人点菜的时候, 服务员就可以去招呼其他客人了, 等客人点好了菜, 直接招呼一声 "服务员", 马上就有个服务员过去服务. 嘿嘿, 然后在老板有了这个新的方法之后, 就进行了一次裁员, 只留了一个服务员! 这就是用单个线程来做多线程的事.
事件多路分解器
大多数现代操作系统提供了一种本机机制, 该机制通过一种有效的方式处理并发和非阻塞资源. 这种机制称为同步事件多路分解器或事件通知借口
使用 Reactor 模式时会发生什么
应用程序向事件多路分解器提交请求来生成新的 I/O 操作. 应用程序还指定一个处理程序, 当操作完成时将调用该处理程序. 向事件多路分解器提交新请求是一种非阻塞调用, 它立即将控制权返回给应用程序
当一组 I/O 操作完成时, 事件多路分解器将新的事件推入 Event Queue(事件队列).
此时, Event Loop 遍历 Event Queue(事件队列).
对于每个事件, 调用关联的处理程序.
处理程序是应用程序代码的一部分, 当它执行完成时将把控制权返还给 Event Loop. 但是, 在处理程序执行过程中可能会请求新的异步操作, 从而导致新的操作被插入事件多路分解器.
当 Event Queue(事件队列) 中所有项目被处理完时, 循环将再次阻塞事件多路分解器 , 当有新事件可用时, 事件多路分解器 将出发另一个周期.
来源: https://www.cnblogs.com/swust-wangyf/p/9344595.html