标签:
通过前边的一篇博文轻量级网络库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是基于同步I/O机制,而Proactor则基于异步I/O机制。这是两者最大的区别。
在博文Comparing Two High-Performance I/O Design Patterns中,作者对这两者给出了很精辟的的解释(不翻译了...人家已经说的很清楚):
“
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:
By comparison, here is a read operation in Proactor (true async):
...
As we mentioned, the true async Proactor pattern requires operating-system-level support.
”
注意上边提到的"The I/O operation ..."指的是真正的I/O操作,如对读缓冲区的读。
关于proactor还可以参考另一文档Proactor。
下边内容摘录自博文libevent源码深度剖析:Reactor模式:
首先来回想一下普通函数调用的机制:程序调用某函数,函数执行,程序等待,函数将结果和控制权返回给程序,程序继续处理。Reactor释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程,应用程序需要提供相应的接口并注册到Reactor上,如果相应的事件发生,Reactor将主动调用应用程序注册的接口,这些接口又称为“回调函数”。使用Libevent也是向Libevent框架注册相应的事件和回调函数;当这些时间发生时,Libevent 会调用这些回调函数处理相应的事件(I/O读写、定时和信号)。
用“好莱坞原则”来形容Reactor再合适不过了:不要打电话给我们,我们会打电话通知你。举个例子:你去应聘某xx公司,面试结束后。“普通函数调用机制”公司HR比较懒,不会记你的联系方式,那怎么办呢,你只能面试完后自己打电话去问结果;有没有被录取啊,还是被据了;“Reactor”公司HR就记下了你的联系方式,结果出来后会主动打电话通知你:有没有被录取啊,还是被拒了;你不用自己打电话去问结果,事实上也不能,你没有HR的联系方式。
Reactor模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:
使用Reactor模型,必备的几个组件:事件源、Reactor框架、多路复用机制和事件处理程序,先来看看Reactor模型的整体框架,接下来再对每个组件做逐一说明。
1 class Reactor 2 { 3 public: 4 int register_handler(Event_Handler *pHandler, int event); 5 int remove_handler(Event_Handler *pHandler, int event); 6 void handle_events(timeval *ptv); 7 // ... 8 };
1 class Event_Handler 2 { 3 public: 4 virtual void handle_read() = 0; 5 virtual void handle_write() = 0; 6 virtual void handle_timeout() = 0; 7 virtual void handle_close() = 0; 8 virtual HANDLE get_handle() = 0; 9 // ... 10 }; 11 class Event_Handler 12 { 13 public: 14 // events maybe read/write/timeout/close .etc 15 virtual void handle_events(int events) = 0; 16 virtual HANDLE get_handle() = 0; 17 // ... 18 };
前面说过Reactor将事件流“逆置”了,那么使用Reactor模式后,事件控制流是什么样子呢?可以参见下面的序列图:
标签:
原文地址:http://www.cnblogs.com/xiehongfeng100/p/4820686.html