加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Proactor和Reactor模式

发布时间:2020-12-15 05:29:47 所属栏目:百科 来源:网络整理
导读:Proactor和Reactor都是并发编程中的设计模式。他们都是用于派发/分离IO操作事件的。所谓的IO事件也就是诸如read/write的IO操作。"派发/分离"就是将单独的IO事件通知到上层模块。两个模式不同的地方在于, Proactor用于异步IO,而Reactor用于同步IO。 Two pat

Proactor和Reactor都是并发编程中的设计模式。他们都是用于派发/分离IO操作事件的。所谓的IO事件也就是诸如read/write的IO操作。"派发/分离"就是将单独的IO事件通知到上层模块。两个模式不同的地方在于,Proactor用于异步IO,而Reactor用于同步IO。

Two patterns that involve event demultiplexors are called Reactor and Proactor。The Reactor patterns involve synchronous I/O,whereas the Proactor pattern involves asynchronous I/O.

下面是一个读的例子(写的例子类同,事件句柄为socket,linux下为文件符)

Reactor:

1 事件句柄注册自己感兴趣的io事件

2 多路事件分发器等待io事件

3 io事件到来并唤醒多路事件分发器,多路器调用应用事件句柄

4 事件句柄进行实际读操作,处理读操作,重新声明感兴趣的io操作,并将控制权返回给多路分发器

Proactor :

1 事件句柄初始化一个异步读操作,此时该句柄并不在意异步操作结果,而是要获得完成事件而注册

2 事件多路器等待直到io事件完成

3 当事件多路器等待io事件时,操作系统在一个并行的内核线程上处理读操作,并将数据放到一个用户定义的缓冲中,并通知事件多路器操作完成。

4 事件多路器调用事件句柄

5 事件句柄从用户定义缓冲中获得用户数据并操作,然后开始新的异步操作并将控释返回事件多路器

可以看出,两个模式的相同点,都是对某个IO事件的通知(即告诉某个模块,这个IO操作可以进行或已经完成)。

在结构上,两者也有相同点:demultiplexor负责提交IO操作(异步)、查询设备是否可操作(同步),然后当条件满足时,就回调handler。
不同点在于,异步情况下(Proactor),当回调handler时,表示IO操作已经完成;同步情况下(Reactor),回调handler时,表示IO设备可以进行某个操作(can read or can write),handler这个时候开始提交操作。

Reactor代码(#add,很显然用的桥模式)

class handler
{
public:
virtual void onRead() = 0;
virtual void onWrite() = 0;
virtual void onAccept() = 0;
};

class dispatch
{
public:
void poll()
{
// add fd in the set.
//
// poll every fd
int c = select( 0,&read_fd,&write_fd,0 );
if( c > 0 )
{
for each fd in the read_fd_set
{
if fd can read
_handler->onRead();
if fd can accept
_handler->onAccept();
}

for each fd in the write_fd_set
{
if fd can write
_handler->onWrite();
}
}
}

void setHandler( handler * pH )
{
_handler = pH;
}

private:
handler *_handler;
};

/// application
class MyHandler : public handler
{
public:
void onRead()
{
}
void onWrite()
{
}
void onAccept()
{
}
};

Proactor:




1、标准定义

两种I/O多路复用模式:Reactor和Proactor

一般地,I/O多路复用机制都依赖于一个事件多路分离器(EventDemultiplexer)。分离器对象可将来自事件源的I/O事件分离出来,并分发到对应的read/write事件处理器(EventHandler)。开发人员预先注册需要处理的事件及其事件处理器(或回调函数);事件分离器负责将请求事件传递给事件处理器。两个与事件分离器有关的模式是Reactor和Proactor。Reactor模式采用同步IO,而Proactor采用异步IO。

在Reactor中,事件分离器负责等待文件描述符或socket为读写操作准备就绪,然后将就绪事件传递给对应的处理器,最后由处理器负责完成实际的读写工作。


而在Proactor模式中,处理器--或者兼任处理器的事件分离器,只负责发起异步读写操作。IO操作本身由操作系统来完成。传递给操作系统的参数需要包括用户定义的数据缓冲区地址和数据大小,操作系统才能从中得到写出操作所需数据,或写入从socket读到的数据。事件分离器捕获IO操作完成事件,然后将事件传递给对应处理器。比如,在windows上,处理器发起一个异步IO操作,再由事件分离器等待IOCompletion事件。典型的异步模式实现,都建立在操作系统支持异步API的基础之上,我们将这种实现称为“系统级”异步或“真”异步,因为应用程序完全依赖操作系统执行真正的IO工作。


举个例子,将有助于理解Reactor与Proactor二者的差异,以读操作为例(类操作类似)。
在Reactor中实现读:

-注册读就绪事件和相应的事件处理器
-事件分离器等待事件
-事件到来,激活分离器,分离器调用事件对应的处理器。
-事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。
在Proactor中实现读:

-处理器发起异步读操作(注意:操作系统必须支持异步IO)。在这种情况下,处理器无视IO就绪事件,它关注的是完成事件。
-事件分离器等待操作完成事件
-在分离器等待过程中,操作系统利用并行的内核线程执行实际的读操作,并将结果数据存入用户自定义缓冲区,最后通知事件分离器读操作完成。
-事件分离器呼唤处理器。
-事件处理器处理用户自定义缓冲区中的数据,然后启动一个新的异步操作,并将控制权返回事件分离器。


可以看出,两个模式的相同点,都是对某个IO事件的事件通知(即告诉某个模块,这个IO操作可以进行或已经完成)。在结构上,两者也有相同点:demultiplexor负责提交IO操作(异步)、查询设备是否可操作(同步),然后当条件满足时,就回调handler;不同点在于,异步情况下(Proactor),当回调handler时,表示IO操作已经完成;同步情况下(Reactor),回调handler时,表示IO设备可以进行某个操作(canreadorcanwrite)。


2、通俗理解

使用Proactor框架和Reactor框架都可以极大的简化网络应用的开发,但它们的重点却不同。

Reactor框架中用户定义的操作是在实际操作之前调用的。比如你定义了操作是要向一个SOCKET写数据,那么当该SOCKET可以接收数据的时候,你的操作就会被调用;而Proactor框架中用户定义的操作是在实际操作之后调用的。比如你定义了一个操作要显示从SOCKET中读入的数据,那么当读操作完成以后,你的操作才会被调用。

Proactor和Reactor都是并发编程中的设计模式。在我看来,他们都是用于派发/分离IO操作事件的。这里所谓的IO事件也就是诸如read/write的IO操作。"派发/分离"就是将单独的IO事件通知到上层模块。两个模式不同的地方在于,Proactor用于异步IO,而Reactor用于同步IO。


3、备注

其实这两种模式在ACE(网络库)中都有体现;如果要了解这两种模式,可以参考ACE的源码,ACE是开源的网络框架,非常值得一学。。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读