两种I/O多路复用模式:Reactor和Proactor编程
通常地,I/O多路复用机制都依赖于一个事件多路分离器(Event Demultiplexer)。分离器对象可未来自事件源的I/O事件分离出来,并分发到对应的read/write事件处理器(Event Handler)。开发人员预先注册须要处理的事件及其事件处理器(或回调函数);事件分离器负责将请求事件传递给事件处理器。两个与事件分离器有关的模式是Reactor和Proactor。Reactor模式采用同步IO,而Proactor采用异步IO。windows
在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设备能够进行某个操做(can read or can write)。socket
使用Proactor框架和Reactor框架均可以极大的简化网络应用的开发,但它们的重点却不一样。函数
Reactor框架中用户定义的操做是在实际操做以前调用的。好比你定义了操做是要向一个SOCKET写数据,那么当该SOCKET能够接收数据的时候,你的操做就会被调用;而Proactor框架中用户定义的操做是在实际操做以后调用的。好比你定义了一个操做要显示从SOCKET中读入的数据,那么当读操做完成之后,你的操做才会被调用。spa
Proactor和Reactor都是并发编程中的设计模式。在我看来,他们都是用于派发/分离IO操做事件的。这里所谓的IO事件也就是诸如read/write的IO操做。"派发/分离"就是将单独的IO事件通知到上层模块。两个模式不一样的地方在于,Proactor用于异步IO,而Reactor用于同步IO。
其实这两种模式在ACE(网络库)中都有体现;若是要了解这两种模式,能够参考ACE的源码,ACE是开源的网络框架,很是值得一学。。