通过前边的一篇博文轻量级网络库libevent初探,我们知道libevent实际上是封装了不同操作系统下的/dev/poll、kqueue、event ports、select、poll和epoll事件机制,从而给我们提供一个统一的接口。

  libevent采用了Reactor I/O 设计模式,而Reactor是基于同步I/O机制的,所以libevent实际是一个基于同步I/O机制的库。

  对于I/O设计模式,与Reactor相对应的还有Proactor。下边我们先来看下这两者的不同之处。

Reactor & Proactor

  Reactor是基于同步I/O机制,而Proactor则基于异步I/O机制。这是两者最大的区别。

  在博文Comparing Two High-Performance I/O Design Patterns中,作者对这两者给出了很精辟的的解释(不翻译了...人家已经说的很清楚):

  “ 

  In general, I/O multiplexing mechanisms rely on an event demultiplexor [13], 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.

  ...

  As we mentioned, the true async Proactor pattern requires operating-system-level support.

  ”

  注意上边提到的"The I/O operation ..."指的是真正的I/O操作,如对读缓冲区的读。

  关于proactor还可以参考另一文档Proactor

  

  下边内容摘录自博文libevent源码深度剖析:Reactor模式

Reactor的事件处理机制

  首先来回想一下普通函数调用的机制:程序调用某函数,函数执行,程序等待,函数将结果和控制权返回给程序,程序继续处理。Reactor释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的事件发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。使用Libevent也是向Libevent框架注册相应的事件和回调函数;当这些时间发生时,Libevent 会调用这些回调函数处理相应的事件(I/O读写、定时和信号)。

  用“好莱坞原则”来形容Reactor再合适不过了:不要打电话给我们,我们会打电话通知你。举个例子:你去应聘某xx公司,面试结束后。“普通函数调用机制”公司HR比较懒,不会记你的联系方式,那怎么办呢,你只能面试完后自己打电话去问结果;有没有被录取啊,还是被拒了;“Reactor”公司HR就记下了你的联系方式,结果出来后会主动打电话通知你:有没有被录取啊,还是被拒了;你不用自己打电话去问结果,事实上也不能,你没有HR的联系方式。

Reactor模式的优点

  Reactor模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:

  • 响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;
  • 编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;
  • 可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源;
  • 可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性;

Reactor模式框架

  使用Reactor模型,必备的几个组件:事件源、Reactor框架、多路复用机制和事件处理程序,先来看看Reactor模型的整体框架,接下来再对每个组件做逐一说明。

  

  1. 事件源
  Linux上是文件描述符,Windows上就是Socket或者Handle了,这里统一称为“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O事件。
  2. event demultiplexer——事件多路分发机制
  由操作系统提供的I/O多路复用机制,比如select和epoll。程序首先将其关心的句柄(事件源)及其事件注册到event demultiplexer上;当有事件到达时,event demultiplexer会发出通知“在已经注册的句柄集中,一个或多个句柄的事件已经就绪”;程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。
  对应到libevent中,依然是select、poll、epoll等,但是libevent使用结构体eventop进行了封装,以统一的接口来支持这些I/O多路复用机制,达到了对外隐藏底层系统机制的目的。
  3. Reactor——反应器
  Reactor,是事件管理的接口,内部使用event demultiplexer注册、注销事件;并运行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。对应到libevent中,就是event_base结构体。
  一个典型的Reactor声明方式:
 class Reactor
{
public:
int register_handler(Event_Handler *pHandler, int event);
int remove_handler(Event_Handler *pHandler, int event);
void handle_events(timeval *ptv);
// ...
};
  4. Event Handler——事件处理程序
  事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供Reactor在相应的事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。对应到libevent中,就是event结构体。下面是两种典型的Event Handler类声明方式,二者互有优缺点。
 class Event_Handler
{
public:
virtual void handle_read() = ;
virtual void handle_write() = ;
virtual void handle_timeout() = ;
virtual void handle_close() = ;
virtual HANDLE get_handle() = ;
// ...
};
class Event_Handler
{
public:
// events maybe read/write/timeout/close .etc
virtual void handle_events(int events) = ;
virtual HANDLE get_handle() = ;
// ...
};

Reactor事件处理流程

  前面说过Reactor将事件流“逆置”了,那么使用Reactor模式后,事件控制流是什么样子呢?可以参见下面的序列图:
  

libevent之Reactor模式的更多相关文章

  1. Reactor模式

    对象行为类的设计模式,对同步事件分拣和派发.别名Dispatcher(分发器) Reactor模式是处理并发I/O比较常见的一种模式,用于同步I/O,中心思想是将所有要处理的I/O事件注册到一个中心I ...

  2. C++服务器设计(一):基于I/O复用的Reactor模式

    I/O模型选择 在网络服务端编程中,一个常见的情景是服务器需要判断多个已连接套接字是否可读,如果某个套接字可读,则读取该套接字数据,并进行进一步处理. 在最常用的阻塞式I/O模型中,我们对每个连接套接 ...

  3. reactor模式---事件触发模型

    Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤. ...

  4. 服务器端编程心得(二)—— Reactor模式

    最近一直在看游双的<高性能linux服务器编程>一书,下载链接: http://download.csdn.net/detail/analogous_love/9673008 书上是这么介 ...

  5. 两种高效的事件处理模型:Reactor模式和Proactor模式

    随着IO多路复用技术的出现,出现了很多事件处理模式.同步I/O模型通常由Reactor模式实现,而异步I/O模型则由Proactor模式实现. Reactor模式: Reator类图如上所示,Reac ...

  6. 高性能服务器开发基础系列 (二)Reactor模式

    系列目录 第01篇 主线程与工作线程的分工 第02篇 Reactor模式 第03篇 一个服务器程序的架构介绍 第04篇 如何将socket设置为非阻塞模式 第05篇 如何编写高性能日志 第06篇 关于 ...

  7. Reactor 模式的简单实现

    Reactor 模式简单实现 在网上有部分文章在描述Netty时,会提到Reactor.这个Reactor到底是什么呢?为了搞清楚Reactor到底是什么鬼,我写了一个简单的Demo,来帮助大家理解他 ...

  8. NIO及Reactor模式

    关于Nio Java NIO即Java Non-blocking IO(Java非阻塞I/O),是Jdk1.4之后增加的一套操作I/O工具包,又被叫做Java New IO. Nio要去解决的问题 N ...

  9. Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/java/nio_reactor/ Java I/O模型 同步 vs. 异步 同步I/O 每个请求必须逐个地被处理,一个请 ...

随机推荐

  1. 多线程(五) Fork/Join框架介绍及实例讲解

    什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过For ...

  2. TCP的TIME_WAIT状态

    主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时 ...

  3. Unity3d导出场景地图寻路

    Unity3d导出场景地图寻路(金庆的专栏)Unity3d中用无渲染的透明盒子摆出地面和阻档区域.        this.renderer.enabled = false;所有这些盒子设为Navig ...

  4. Maven坐标机制

    Maven为所有的项目引入了坐标,基于坐标机制可以唯一定位一个项目. 坐标详解 以spring-core-2.5.6.jar的坐标定义为例,说明组成坐标的所有元素:groupId.artifactId ...

  5. 2.cocos2dx 3.2中语法的不同之处,lambada表达式的使用和function和bind函数的使用

    1        打开建好的T32  Cocos2dx-3.2的一个项目 2        设置Cocos显示窗口的位置是在AppDelegate.cpp中: 3  设置自适应窗口大小的代码是在上面的 ...

  6. 如何查看Android设备上的分区信息

    Android设备上,一般都会存在一块eMMC存储芯片来存放系统和用户数据,甚至部分的引导程序. 一般设备出厂时,各个厂商都会将这块存储芯片分成很多的分区,每个分区内存放不同的内容.具体分区的布局每个 ...

  7. J2EE进阶(九)org.hibernate.LazyInitializationException: could not initialize proxy - no Session

    org.hibernate.LazyInitializationException: could not initialize proxy - no Session 前言 在<many-to-o ...

  8. Redis主从和HA配置

    1同步原理 摘自:http://www.cnblogs.com/stephen-liu74/archive/2012/03/30/2364717.html "下面的列表清楚的解释了Redis ...

  9. Douglas Adams - 3 Rules That Describe Our Reactions To Technologies 科技影响生活的三个规律

    文章摘自http://highscalability.com/. 这个博客是大家都应该订阅的.原文地址http://highscalability.com/blog/2014/3/11/douglas ...

  10. WIP 投料报 Invalid Serial Number

    1.接口表数据检查无误 2.同样数据界面能正常完成 界面做trace SQL ID: b2mw8gjyv7guh Plan Hash: 2015965341 DELETE FROM MTL_SERIA ...