前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >程序设计中的两大经典模式 -- Reactor & Proactor

程序设计中的两大经典模式 -- Reactor & Proactor

作者头像
用户3147702
发布2022-06-27 14:39:59
1.2K0
发布2022-06-27 14:39:59
举报
文章被收录于专栏:小脑斧科技博客

1. 引言

Reactor 与 Proactor 模型是近几年技术领域频频提到的两个设计模式,那么,究竟什么是 Reator,什么又是 Proactor,他们之间有什么异同呢? 本文就来详细介绍一下。

2. UNIX 下的五种 IO 模型

此前,我们已经介绍过 linux 系统中的五种 IO 模型: IO复用 & UNIX下的五种IO模型

在 IO 模型中,IO 复用模型,例如 epoll、select 等就是在 Reator 思想下诞生的,而异步 IO 模型,例如 glibc 实现的 posix aio 或是 linux 原生的 libaio 就是在 Proactor 思想下诞生的。 如果你非常熟悉 IO 复用模型与异步 IO 模型之间的差异,那么,关于 Reactor 与 Proactor 思想的区别就非常清晰了。

3. Reactor 模式

3.1. 模式构成

Reactor包含以下角色:

  1. Handle 句柄 — 在 linux 中,就是常见的文件描述符,用来标识 socket 连接或是打开的文件
  2. Reactor — 反应器,定义抽象接口,实现:
    1. 供应用程序注册和删除关注的事件句柄
    2. 运行事件循环
    3. 有就绪事件到来时,分发事件到之前注册的回调函数上处理 Synchronous Event Dispatcher — 同步事件多路分发器,由操作系统内核实现,用于阻塞等待发生在句柄上的一个或多个事件,我们系统中的 select、poll、epoll 等多路复用 IO 就充当了这一角色。

3. Event Handler — 事件处理接口。

3.2. 工作时序

下面展示了整个 Reactor 模式工作的时序:

整体的思想分为以下几步:

  1. 初始化启动应用,将事件注册到 Reactor 中
  2. 调用 get_handle() 接口,获取事件处理对象
  3. 调用 Reactor 进入事件循环,等待注册的事件到来
  4. 注册的事件触发,select() 返回,Reactor 回调已注册的回调函数

这一思想就是基于经典的回调思想“不要调用我,让我来调用你”的“好莱坞法则”设计的,具体的执行过程可以参看 epoll 的使用

4. Proactor 模式

Proactor 模式是另一个消息异步通知的设计模式,与 Reactor 的最大区别在于,Proactor 通知的不是就绪事件,而是操作完成事件,这也就是操作系统异步 IO 的主要模型。

4.1. 模式构成

Proactor 模式包含以下角色:

  1. Handle 句柄 — 在 linux 中,就是常见的文件描述符,用来标识 socket 连接或是打开的文件
  2. Asynchronous Operation Processor — 异步操作处理器;负责执行异步操作,一般由操作系统内核实现,也可以被用户态线程或进程模拟
  3. Asynchronous Operation — 异步操作
  4. Completion Event Queue — 完成事件队列,用来缓存已经完成的异步操作
  5. Proactor — 主动器,定义抽象接口,实现:
    1. 为应用程序进程提供事件循环
    2. 从完成事件队列中取出异步操作的结果
    3. 分发调用已完成时间相应的后续处理逻辑
  6. Completion Handler — 完成事件接口,一般是由回调函数组成的接口。
  7. Concrete Completion Handler — 完成事件后的具体处理逻辑,实现接口定义特定的应用处理逻辑。

4.2. 模式执行时序

下图展现了 Proactor 执行的时序:

主要分为以下几步:

  1. 初始化启动,注册异步操作完成后的回调操作
  2. 主程序调用异步操作处理器提供的异步操作接口
  3. Asynchronous Operation Processor 执行异步操作,完成后将结果放入事件完成队列
  4. Proactor 从完成事件队列中取出结果,分发到相应的完成事件回调函数处理逻辑中

5. 优势与不足

5.1. 主动与被动 — Reactor 与 Proactor 的区别

Reactor 调用后,需要被动等待对象进入就绪状态,然后再进行后续处理。 Proactor 则会待操作完全完成后由内核返回,主进程可以主动切换去执行其他任务。

5.2. Reactor 的优势与不足

5.2.1. 优势

Reactor 在实现上相对比较简单,对于大量对象,频繁从非就绪态触发到就绪态的场景处理十分高效。 同时,操作系统可以同时去等待多个对象触发,并且可以在事件触发后自由地选择后续执行流程,具有很高的灵活性。 虽然并发编程实现阻塞式同步 IO 也可以实现同时等待多个对象触发的效果,但在编程的复杂度与资源的消耗等方面,Reactor 模式拥有明显的优势。

5.2.2. 不足

但是 Reactor 的不足也很明显,如果就绪态长时间没有触发,则进程一直等待,长时间阻塞主进程,影响到整个系统的吞吐。

5.3. Proactor 的优势与不足

此前我们介绍了 glibc 实现的 POSIX aio 与 linux 原生实现的 libaio,他们是典型的 Proactor 模式的处理模型: POSIX AIO — glibc 版本异步 IO 简介 linux AIO — libaio 实现的异步 IO 简介及实现原理

5.3.1. 优势

Proactor 最显著的优势在于处理耗时长的 IO 操作和并发场景。 同时,针对 IO 操作,一旦提交,内核只有在完全执行完成后才会再次通知到用户进程,在这个过程中,用户进程可以做任何其他操作,这给与了用户进程更大的灵活性。

5.3.2. 不足

Proactor 的实现相对比较复杂,在实际编程中,与基本的同步 IO 相比,aio 在使用上也不那么容易,尤其是 linux 的 libaio 具有五个 api,同时需要自己构造执行上下文和 buffer,性能与 windows 下的 IOCP 相比也有一定的差距,普通场景中还是不建议使用 linux 的 aio 的。

6. 参考资料

http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf。 https://en.wikipedia.org/wiki/Reactor\_pattern。 https://en.wikipedia.org/wiki/Proactor\_pattern。 https://www.dre.vanderbilt.edu/~schmidt/PDF/Proactor.pdf。 http://lse.sourceforge.net/io/aio.html。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 引言
  • 2. UNIX 下的五种 IO 模型
  • 3. Reactor 模式
    • 3.1. 模式构成
      • 3.2. 工作时序
      • 4. Proactor 模式
        • 4.1. 模式构成
          • 4.2. 模式执行时序
          • 5. 优势与不足
            • 5.1. 主动与被动 — Reactor 与 Proactor 的区别
              • 5.2. Reactor 的优势与不足
                • 5.2.1. 优势
                • 5.2.2. 不足
              • 5.3. Proactor 的优势与不足
                • 5.3.1. 优势
                • 5.3.2. 不足
            • 6. 参考资料
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档