浅谈 I/O 设计模块之:Reactor和Proactor对比

综述

对于 I/O 设计模式,网上有许多文章,都详细地介绍了Reactor和Proactor两种设计模式各自的概念和优劣。如还未阅读过相关概念,可以参考:IO设计模式:Reactor和Proactor对比 、 IO多路复用机制详解 这两篇文章。两种模式的具体概念这里就不再赘述,只谈个人对这两种设计模式的理解。

Reactor和Proactor

所谓Reactor和Proactor,在我个人的理解,其实就是 ”被动器“和”主动器“。
Reactor和Proactor都需要将事件分发到相应的回调处理函数中处理(通知用户线程),两者最重要的区别就在于:

  1. 交给用户线程的数据是否经过处理
  2. 是如何获取事件的是如何获取事件的是如何获取事件的

重要的事说三遍。

Reactor

在Reactor模式下,可以理解为当I/O事件触发的一瞬间,Reactor立即该事件分发给相应的回调处理函数,即通知了用户线程(虽然在实现上,对事件的获取一般是采用无限循环,轮询查询,等待注册事件的到来,而不是“通知”的形式。如果看晕了,可以先不看该括号中的内容。)

Proactor

在Proactor模式下,可以理解为当I/O事件触发的一瞬间,Proactor啥也不干。是的,你没有看错,Proactor啥也不干。为什么这么说呢?因为Proactor下对事件的获取是主动去获取的。当I/O事件到来时,其自动进入一个队列中,或者说一个容器中。当然进入容器前可能还要做一些处理,比如将数据写入用户指定的缓存区等。而Proactor只需要主动地去该容器中取事件,将IO完成的信息通知给用户线程(一般通过调用用户线程注册的完成事件处理函数)。

解释

上面说的非常拗口,可能会越看越晕,下面来看一些通俗的解释。

用户线程可以理解为一个老大,他有两个小弟。一个叫Reactor,一个叫Proactor。老大在全国各地都订了货物,这些货物最后都会送到一个窗口(socket),他派他的两个小弟去窗口接收货物,当有货物到来时喊他。

Reactor就一直坐在窗口前等,等当一个货物到来,送货员就拍拍Reactor的肩膀(被动获取),Reactor就立马拿着这个货物去找老大,让老大自己处理这批货物(读取数据),当然老大可能是自己处理,也可能是派几个小弟处理,但是这已经跟Reactor没关系了。之后Reactor再跑回窗口继续等。

Proactor就不一样了,他拿了一个盒子(队列、容器)。他跟送货的人说,货来了以后,你就扔到这个盒子里面就行了,然后就跑到一旁玩王者荣耀去了。每打完一把或者每次死的时候过来看看盒子(主动获取),如果盒子里面不是空的,他就把里面的货拿出来,有几个货就再喊几个小弟(开线程),让这些小弟处理这批货物(处理数据)。甚至他可以让这些小弟直接把处理完的货物放到老大家里(用户线程指定的缓存区)。
完事了以后,他让小弟跟老大打声招呼就行。

优劣对比

参考 IO设计模式:Reactor和Proactor对比 中的对比模块,不再赘述。

总结

相比于IO多路复用模型,异步IO并不十分常用,不少高性能并发服务程序使用IO多路复用模型+多线程任务处理的架构基本可以满足需求。况且目前操作系统对异步IO的支持并非特别完善,更多的是采用IO多路复用模型模拟异步IO的方式(IO事件触发时不直接通知用户线程,而是将数据读写完毕后放到用户指定的缓冲区中。

你可能感兴趣的:(设计模式)