前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >IO设计模式之Reactor和Proactor

IO设计模式之Reactor和Proactor

作者头像
我是攻城师
发布2018-12-17 17:18:48
3.2K1
发布2018-12-17 17:18:48
举报
文章被收录于专栏:我是攻城师我是攻城师

前言

上面文章中,我们提到不同的操作系统实现的io策略可能不一样,即使是同一个操作系统也可能存在多重io策略,常见如linux上的select,poll,epoll,面对这么多不同类型的io接口,这里需要一层抽象api来完成,所以就演变出来两种高性能的io的设计模式,分别是Reactor(同步IO)和Proactor(异步IO)。

一般情况下,I/O 复用机制需要事件分享器(event demultiplexor)。 事件分离器的作用,即将那些读写事件源分发给各读写事件的处理者,就像送快递的小哥,拉着一三轮车快递停到了小区的快递收发区,然后打电话通知,谁谁谁的快递到了快来拿吧;谁谁谁要邮寄出去的快递,快来这里邮寄填写表格。这里面拿快递就类似IO的读请求,发快递就类似IO的写请求,而快递小哥则是事件分享器,并负责完成送和收快递的两种事件。开发人员在开始的时候需要在分享器那里注册感兴趣的事件,并提供相应的处理者(event handlers),或者是回调函数; 事件分享器在适当的时候会将请求的事件分发给这些handler或者回调函数。

关于Reactor

Reactor英文意思为反应器,类似于核能的反应堆一样,所有的能量都源源不断从这里传出.或者更贴切一点叫事件的分发器。在Reactor中,事件分离器负责等待文件描述符或socket为读写操作准备就绪,然后将就绪事件传递给对应的处理器,最后由处理器负责完成实际的读写工作。

Linux epoll 使用 Reactor 模式。Reactor 模式使用同步 I/O(一般来说)。Reactor 的标准(典型)的工作方式是:

(1)应用程序注册读就绪事件和相关联的事件处理器

(2)Reactor阻塞等待内核事件通知

(3)Reactor收到通知,然后分发可读写事件(读写准备就绪)到用户事件处理函数

(4)用户读取数据,并处理数据

(5)事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。

这里面需要注意,事件分离器仅仅发现当有io事件都写就绪的时候,会通知用户线程来读取数据,这一步相当于io阻塞的第二个阶段,从内核空间拷贝数据到用户空间是由用户线程完成的,所以Reactor模式实际上还属于同步IO的模式,当然为了架构更灵活和性能更好,一般情况下事件分离器和实际的处理器线程是分开的,类似Netty里面的boss线程组合worker线程组一样。

关于Proactor

Proactor英文意思前摄器,是一种异步的IO设计模式。这种模式更加理想,但真正支持纯异步的io模式,目前只有windows的Windows IO completion port.(iocp)模型。

Windows iocp 使用 Praactor 模式。Praactor 模式使用异步 I/O(一般来说)。Praactor 的标准(典型)的工作方式是:

(1)应用程序初始化一个异步读取操作,然后注册相应的事件处理器,此时事件处理器不关注读取就绪事件,而是关注读取完成事件,这是区别于Reactor的关键。

(2)事件分离器等待读取操作完成事件

(3)在事件分离器等待读取操作完成的时候,操作系统调用内核线程完成读取操作,并将读取的内容放入用户传递过来的缓存区中。这也是区别于Reactor的一点,Proactor中,应用程序需要传递缓存区。

(4)事件分离器捕获到读取完成事件后,激活应用程序注册的事件处理器,事件处理器直接从缓存区读取数据,而不需要进行实际的读取操作。

从上面的描述中能够看到,Proactor模式中,操作系统相当于直接把IO操作的两阶段工作都给干了,这也要求应用程序在注册异步任务时,需要传递一个缓存区,用来存放结果数据。这里面事件分离器关注的是io的完成事件,而不是就绪时间,当分离器通知应用程序时,应用程序可以直接就能处理数据了。

总结

关于Reactor和Proactor这两种IO设计模式,我们举个实际生活中的例子:Reactor模式就是快递员在楼下,给你打电话告诉你快递到了,你需要自己下楼来拿快递。而在Proactor模式下,快递员直接将快递送到家里面的指定位置。

Reactor和Proactor是两种高性能的IO设计模式,分别用于同步IO和异步IO的策略,可以看出它们都是采用的IO复用的模式,都是对某个IO事件的事件通知(即告诉某个模块,这个IO操作可以进行或已经完成)。在结构上,两者也有相同点:demultiplexor负责提交IO操作(异步)、查询设备是否可操作(同步),然后当条件满足时,就回调handler;

不同点在于,异步情况下(Proactor),当回调handler时,表示IO操作已经完成(数据已从系统内核拷贝到程序内存);同步情况下(Reactor),回调handler时,表示IO设备可以进行某个操作(can read or can write,数据准备就绪,但是用户需要自己将数据从系统内核拷贝到程序内存)。

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

本文分享自 我是攻城师 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 关于Reactor
  • 关于Proactor
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档