博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

两种IO模式:Proactor与Reactor模式

Posted on 2014-09-15 17:58  bw_0927  阅读(195)  评论(0)    收藏  举报

http://www.chinaxing.org/articles/linux/2013/08/06/2013-08-06-proactor-vs-reactor.html

http://blog.csdn.net/summerhust/article/details/8035694

真正的异步模式需要操作系统级别的支持。

 

IO多路复用模型有两种Proactor与Reactor,两者的区别主要在于IO是同步还是异步

Proactor比Reactor更高效。

下面是两种模式的请求处理过程:

处理过程

 

Proactor

  1. client创建要进行的操作,并注册操作完成时的回调处理函数
  2. 操作(opration)交由操作系统底层进行处理
  3. 处理完成后底层将操作结果和回调函数传给Proactor调度器
  4. Proactor调度器进行分发事件,调用具体的回调处理函数。

Reactor

  1. 对事件进行注册处理函数。
  2. client的请求触发底层的事件。
  3. Reactor调度器检查事件发生,执行注册的处理函数。

区别和联系

 

区别

在实现中,Proactor是发出异步IO请求,交由操作系统完成IO请求,然后回调自己。

而Reactor是查询操作系统,发生事件的时候,自己再对操作系统同步IO请求,完成后再回调注册的处理函数。

因此二者的区别在于IO请求是OS来做,还是应用层来做,即异步与同步IO。

异步IO在windows上比较成熟,支持完善和高效,而在Linux等Unix系列操作系统上支持的不是很好,所以大多以Reactor模式为主。

联系

涉及到高效IO框架都使用了IO多路复用与基于事件的方式,来将请求的处理过程“交叉化”,并行化,异步化,同时尽量的使用底层OS提供的支持功能来达到高效。

参考材料

=======================

 

Standard/classic Reactor:

 

  • Step 1) wait for event (Reactor job)
  • Step 2) dispatch "Ready-to-Read" event to user handler ( Reactor job)
  • Step 3) read data (user handler job)
  • Step 4) process data ( user handler job)

 

Proposed emulated Proactor:

 

  • Step 1) wait for event (Proactor job)
  • Step 2) read data (now Proactor job)
  • Step 3) dispatch "Read-Completed" event to user handler (Proactor job)
  • Step 4) process data (user handler job)

 

 

==================================

http://www.cnblogs.com/hello-leo/archive/2011/04/08/2009432.html

简单看了下boost.asio的源码,因为asio采用proactor模式,而windows下的IOCP本身就是这个模式的体现,所以将精力 集中在了asio在linux下的实现(asio在windows下采用了IOCP,linux下用epoll,还有其它的一些实现如 kqueue,select等).

在高性能服务器并发模型设计中,Reactor和Proactor是两个经常用到的设计模式,前者用于同步IO,后者用于异步IO,前者在IO操作 就绪的情况下通知用户,用户再采取实际的IO操作,后者是在IO操作完成后通知用户,举个简单的例子,比如说你有一封信到了邮局,Reactor模式就是 邮局的人到你家来告诉你说你有信件,然后你到邮局去拿,而Proactor模式则是邮局的把信件送到了你家.在我看来IOCP的设计就是Proactor 模式的完美体现,而epoll则很容易实现Reactor模式,asio设计为跨平台,并且在linux下采用epoll,我的印象中linux对异步 IO的支持没有windows那么完善(看看IOCP和epoll模型的区别就知道),那么asio是怎么用epoll机制实现proactor模式的 呢,刚开始想的是应该在应用层做了一层封装,就是asio内部应该有某个循环调用epoll_wait,当有IO事件就绪时帮用户做一些操作(比如把数据 拷贝到我们提交的缓冲区),然后在操作完成的时候调用我们的handler(后来看代码基本是这样).OK,不说废话了.

 

 

==============================

Reactor关注操作就绪通知,收到通知后程序得自己调用相应的系统API来进程IO操作,比如读写socket。

而Proactor模式它关注操作完成通知,收到通知时系统已经帮你完成了IO操作,比如缓冲区里的数据已经被发送出去了或者缓冲区里已经有了接收到的数据。

 

==========================================================

http://www.artima.com/articles/io_design_patterns2.html

Reactor and Proactor: two I/O multiplexing approaches

In general, I/O multiplexing mechanisms rely on an event demultiplexor [1, 3], an object that dispatches I/O events from a limited number of sources to the appropriate read/write event handlers. The developer registers interest in specific events and provides event handlers, or callbacks. The event demultiplexor delivers the requested events to the event handlers.

Two patterns that involve event demultiplexors are called Reactor and Proactor [1]. The Reactor patterns involve synchronous I/O, whereas the Proactor pattern involves asynchronous I/O. In Reactor, the event demultiplexor waits for events that indicate when a file descriptor or socket is ready for a read or write operation. The demultiplexor passes this event to the appropriate handler, which is responsible for performing the actual read or write.

In the Proactor pattern, by contrast, the handler—or the event demultiplexor on behalf of the handler—initiates asynchronous read and write operations. The I/O operation itself is performed by the operating system (OS). The parameters passed to the OS include the addresses of user-defined data buffers from which the OS gets data to write, or to which the OS puts data read. The event demultiplexor waits for events that indicate the completion of the I/O operation, and forwards those events to the appropriate handlers. For example, on Windows a handler could initiate async I/O (overlapped in Microsoft terminology) operations, and the event demultiplexor could wait for IOCompletion events [1]. The implementation of this classic asynchronous pattern is based on an asynchronous OS-level API, and we will call this implementation the "system-level" or "true" async, because the application fully relies on the OS to execute actual I/O.

An example will help you understand the difference between Reactor and Proactor. We will focus on the read operation here, as the write implementation is similar. Here's a read in Reactor:

  • An event handler declares interest in I/O events that indicate readiness for read on a particular socket
  • The event demultiplexor waits for events
  • An event comes in and wakes-up the demultiplexor, and the demultiplexor calls the appropriate handler
  • The event handler performs the actual read operation, handles the data read, declares renewed interest in I/O events, and returns control to the dispatcher

By comparison, here is a read operation in Proactor (true async):

  • A handler initiates an asynchronous read operation (note: the OS must support asynchronous I/O). In this case, the handler does not care about I/O readiness events, but is instead registers interest in receiving completion events.
  • The event demultiplexor waits until the operation is completed
  • While the event demultiplexor waits, the OS executes the read operation in a parallel kernel thread, puts data into a user-defined buffer, and notifies the event demultiplexor that the read is complete
  • The event demultiplexor calls the appropriate handler;
  • The event handler handles the data from user defined buffer, starts a new asynchronous operation, and returns control to the event demultiplexor.