Linux -- Proactor(及其与Reactor的比较)

高并发服务器常由多线程+IO复用服务器(one event loop per thread)html

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

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

 

在Reactor中,事件分离器负责等待文件描述符或socket为读写操做准备就绪,而后将就绪事件传递给对应的处理器,最后由事件处理器负责完成实际的读写工做。而在Proactor模式中,处理器或者兼任处理器的事件分离器,只负责发起异步读写操做。IO操做自己由操做系统来完成。传递给操做系统的参数须要包括用户定义的数据缓冲区地址和数据大小,操做系统才能从中获得写出操做所需数据,或写入从socket读到的数据。事件分离器捕获IO操做完成事件,而后将事件传递给对应处理器。好比,在windows上,处理器发起一个异步IO操做,再由事件分离器等待IOCompletion事件。典型的异步模式实现,都创建在操做系统支持异步API的基础之上,咱们将这种实现称为“系统级”异步或“真”异步,由于应用程序彻底依赖操做系统执行真正的IO工做。以读操做为例:编程

 

在Reactor中实现读:segmentfault

- 注册读就绪事件和相应的事件处理器windows

- 事件分离器等待事件设计模式

- 事件到来,激活分离器,分离器调用事件对应的处理器。服务器

- 事件处理器完成实际的读操做,处理读到的数据,注册新的事件,而后返还控制权。网络

 

在Proactor中实现读:多线程

- 处理器发起异步读操做(注意:操做系统必须支持异步IO)。在这种状况下,处理器无视IO就绪事件,它关注的是完成事件。并发

- 事件分离器等待操做完成事件

- 在分离器等待过程当中,操做系统利用并行的内核线程执行实际的读操做,并将结果数据存入用户自定义缓冲区,最后通知事件分离器读操做完成。

- 事件分离器呼唤处理器。

- 事件处理器处理用户自定义缓冲区中的数据,而后启动一个新的异步操做,并将控制权返回事件分离器。

 

经过上例能够看出,两个模式的相同点,都是对某个IO事件的事件通知(即告诉某个模块,这个IO操做能够进行或已经完成)。在结构上,二者也有相同点:demultiplexor负责提交IO操做(异步)、查询设备是否可操做(同步),而后当条件知足时,就回调handler;不一样点在于,异步状况下(Proactor),当回调handler时,表示IO操做已经完成;同步状况下(Reactor),回调handler时,表示IO设备能够进行某个操做(can read or can write)。

 

使用Proactor框架和Reactor框架均可以极大的简化网络应用的开发,但它们的重点却不一样。Reactor框架中用户定义的操做是在实际操做以前调用的。好比你定义了操做是要向一个SOCKET写数据,那么当该SOCKET能够接收数据的时候,你的操做就会被调用;而Proactor框架中用户定义的操做是在实际操做以后调用的。好比你定义了一个操做要显示从SOCKET中读入的数据,那么当读操做完成之后,你的操做才会被调用。

 

Proactor和Reactor都是并发编程中的设计模式。在我看来,他们都是用于派发/分离IO操做事件的。这里所谓的IO事件也就是诸如read/write的IO操做。"派发/分离"就是将单独的IO事件通知到上层模块。两个模式不一样的地方在于,Proactor用于异步IO,而Reactor用于同步IO。目前应用最普遍的是Reactor模boost::asio,ACE和Windows I/O Completion Ports 实现了Proactor 模式,应用面彷佛要窄一些。

 

Proactor (论文翻译提要)

原文: http://www.cs.wustl.edu/~schmidt/PDF/proactor.pdf

结构

1. proacitve initiator (Web server application’s main thread)

       proactive Initiator是应用中启动异步操做的实体.proactive initiator注册一个completion handler和一个completion dispatcher,以及一个asynchronous Operation Processor, asynchronous Operation Processor的做用是当操做完成将会通知.

2.Completion Handler(the acceptor and http handler)

       Proactor模式使用completion handler接口用来得到异步操做完成的通知.

3.Asynchronous Operation

        异步操做,由系统API实现,如async_read,async_write,async_accept等.异步操做用来执行异步请求(如i/o或定时器.).当应用请求异步操做时,该操做不会占用应用(主)线程.所以,从整个应用的角度来看,操做表现为异步.当异步操做完成,异步操做处理器(Asynchronous         Operation Processor)将通知完成操做分发器(Completion Dispatcher)

4. Asynchronous Operation Processor(操做系统)

        异步操做由异步操做处理器(Asynchronous Operation Processor)执行完成.该组件由操做系统实现.

5. Completion Dispatcher (the Notification Queue)

        完成分发器的做用是,当异步操做完成时,把Completion handler返回给应用,即proacitve initiator

流程

1.主动启动器(proacitve initiator)启动操做

        为了表现为异步操做,应用在异步操做处理器中启动操做.举例:一个web server向OS请求经过网络向某个特定的socket connetion发送一个文件.web server应该指定当操做完成去通知哪个completion handler,以及当文件传送完成后哪个completion dispatcher去callback.

2.异步操做处理器执行操做.

       当应用在异步操做处理器上请求操做,异步操做处理器异步地执行这些操做.现代操做系统在内核中提供了异步IO.

3.异步操做处理器通知完成分发器

       当异步操做完成,异步操做处理器检索特定的completion handler和completion dispatcher.(在第1步时指定的).而后异步操做处理器把异步操做的结果(the result of the Asynchronous Operation)和要返回的comletion handler(the Completion Handler to call back)传递给completion dispatcher.举例:当文件成功地被异步发送出,异步操做处理器将会报告完成状态(成功或失败),同时the number of bytes written to the network connection.

4.完成分发器通知应用程序.

        举例:例如一个异步读操做完成后,completion handler 将被传入一个指向newly arrived data的指针.

 

如下是POSA2中的proactor模型

http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/overview/core/async.html

http://www.javashuo.com/article/p-qfjdxnhn-q.html

多了一个proactor,completion dispatcher 改成completion event queue.

流程

  1. Initiator启动proactor.proactor内是event loop等待完成事件的到来.
  2. 有请求到来,initiator请求asy operation processor执行异步操做.异步操做完成后,将结果返回给asy operation processor.asy operation processor将结果放入到completion event queue.
  3. Proactor进行event loop,等待completion event的到来.当queue中存在completion event,proactor得到此完成事件并把事件结果传递给completion handler

 

 

以主动写为例:

  • Reactor将handle放到select(),等待可写就绪,而后调用write()写入数据;写完处理后续逻辑;
  • Proactor调用aoi_write后马上返回,由内核负责写操做,写完后调用相应的回调函数处理后续逻辑;
相关文章
相关标签/搜索