该文章总结了网上资源对这两种模式的描述html
原文地址:http://www.cnblogs.com/dawen/archive/2011/05/18/2050358.htmlreact
两种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)。并发
使用Proactor框架和Reactor框架均可以极大的简化网络应用的开发,但它们的重点却不一样。
Reactor框架中用户定义的操做是在实际操做以前调用的。好比你定义了操做是要向一个SOCKET写数据,那么当该SOCKET能够接收数据的时候,你的操做就会被调用;而Proactor框架中用户定义的操做是在实际操做以后调用的。好比你定义了一个操做要显示从SOCKET中读入的数据,那么当读操做完成之后,你的操做才会被调用。
Proactor和Reactor都是并发编程中的设计模式。在我看来,他们都是用于派发/分离IO操做事件的。这里所谓的IO事件也就是诸如read/write的IO操做。"派发/分离"就是将单独的IO事件通知到上层模块。两个模式不一样的地方在于,Proactor用于异步IO,而Reactor用于同步IO。
其实这两种模式在ACE(网络库)中都有体现;若是要了解这两种模式,能够参考ACE的源码,ACE是开源的网络框架,很是值得一学。。
原文地址:http://daimojingdeyu.iteye.com/blog/828696
Reactor这个词译成汉语还真没有什么合适的,不少地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些。经过了解,这个模式更像一个侍卫,一直在等待你的召唤,或者叫召唤兽。
并发系统常使用reactor模式,代替经常使用的多线程的处理方式,节省系统的资源,提升系统的吞吐量。
先用比较直观的方式来介绍一下这种方式的优势,经过和经常使用的多线程方式比较一下,可能更好理解。
以一个餐饮为例,每个人来就餐就是一个事件,他会先看一下菜单,而后点餐。就像一个网站会有不少的请求,要求服务器作一些事情。处理这些就餐事件的就须要咱们的服务人员了。
在多线程处理的方式会是这样的:
一我的来就餐,一个服务员去服务,而后客人会看菜单,点菜。 服务员将菜单给后厨。
二我的来就餐,二个服务员去服务……
五我的来就餐,五个服务员去服务……
这个就是多线程的处理方式,一个事件到来,就会有一个线程服务。很显然这种方式在人少的状况下会有很好的用户体验,每一个客人都感受本身是VIP,专人服务的。若是餐厅一直这样同一时间最多来5个客人,这家餐厅是能够很好的服务下去的。
来了一个好消息,由于这家店的服务好,吃饭的人多了起来。同一时间会来10个客人,老板很开心,可是只有5个服务员,这样就不能一对一服务了,有些客人就要没有人管了。老板就又请了5个服务员,如今好了,又能每一个人都受VIP待遇了。
愈来愈多的人对这家餐厅满意,客源又多了,同时来吃饭的人到了20人,老板高兴不起来了,再请服务员吧,占地方不说,还要开工钱,再请人就攒不到钱了。怎么办呢?老板想了想,10个服务员对付20个客人也是能对付过来的,服务员勤快点就行了,伺候完一个客人立刻伺候另一个,仍是来得及的。综合考虑了一下,老板决定就使用10个服务人员的线程池啦~~~
可是这样有一个比较严重的缺点就是,若是正在接受服务员服务的客人点菜很慢,其余的客人可能就要等好长时间了。有些火爆脾气的客人可能就等不了走人了。
Reactor如何处理这个问题呢:
老板后来发现,客人点菜比较慢,大部服务员都在等着客人点菜,其实干的活不是太多。老板能当老板固然有点不同的地方,终于发现了一个新的方法,那就是:当客人点菜的时候,服务员就能够去招呼其余客人了,等客人点好了菜,直接招呼一声“服务员”,立刻就有个服务员过去服务。嘿嘿,而后在老板有了这个新的方法以后,就进行了一次裁人,只留了一个服务员!这就是用单个线程来作多线程的事。
实际的餐馆都是用的Reactor模式在服务。一些设计的模型其实都是从生活中来的。
Reactor模式主要是提升系统的吞吐量,在有限的资源下处理更多的事情。
在单核的机上,多线程并不能提升系统的性能,除非在有一些阻塞的状况发生。不然线程切换的开销会使处理的速度变慢。就像你一我的作两件事情,一、削一个苹果。二、切一个西瓜。那你能够一件一件的作,我想你也会一件一件的作。若是这个时候你使用多线程,一下子削苹果,一会切西瓜,能够相像到底是哪一个速度快。这也就是说为何在单核机上多线程来处理可能会更慢。
但当有阻碍操做发生时,多线程的优点才会显示出来,如今你有另外两件事情去作,一、削一个苹果。二、烧一壶开水。我想没有人会去作完一件再作另外一件,你确定会一边烧水,一边就把苹果削了。
理论的东西就很少讲了,请你们参考一下附件《reactor-siemens.pdf》。图比较多,E文很差也能够看懂的。
下载地址:http://files.cnblogs.com/files/lfsblack/reactor.pdf
原文地址:http://xmuzyq.iteye.com/blog/783218
在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操做。
在比较这两个模式以前,咱们首先的搞明白几个概念,什么是阻塞和非阻塞,什么是同步和异步,同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操做并等待或者轮询的去查看IO操做是否就绪,而异步是指用户进程触发IO操做之后便开始作本身的事情,而当IO操做已经完成的时候会获得IO完成的通知。而阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操做的就绪状态来采起的不一样方式,说白了是一种读取或者写入操做函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会当即返回一个状态值。
通常来讲I/O模型能够分为:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞IO
同步阻塞IO:
在此种方式下,用户进程在发起一个IO操做之后,必须等待IO操做的完成,只有当真正完成了IO操做之后,用户进程才能运行。JAVA传统的IO模型属于此种方式!
同步非阻塞IO:
在此种方式下,用户进程发起一个IO操做之后边可返回作其它事情,可是用户进程须要时不时的询问IO操做是否就绪,这就要求用户进程不停的去询问,从而引入没必要要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。
异步阻塞IO:
此种方式下是指应用发起一个IO操做之后,不等待内核IO操做的完成,等内核完成IO操做之后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为何说是阻塞的呢?由于此时是经过select系统调用来完成的,而select函数自己的实现方式是阻塞的,而采用select函数有个好处就是它能够同时监听多个文件句柄,从而提升系统的并发性!
异步非阻塞IO:
在此种模式下,用户进程只须要发起一个IO操做而后当即返回,等IO操做真正的完成之后,应用程序会获得IO操做完成的通知,此时用户进程只须要对数据进行处理就行了,不须要进行实际的IO读写操做,由于真正的IO读取或者写入操做已经由内核完成了。目前Java中尚未支持此种IO模型。
搞清楚了以上概念之后,咱们再回过头来看看,Reactor模式和Proactor模式。
首先来看看Reactor模式,Reactor模式应用于同步I/O的场景。咱们分别以读操做和写操做为例来看看Reactor中的具体步骤:
读取操做:
1. 应用程序注册读就需事件和相关联的事件处理器
2. 事件分离器等待事件的发生
3. 当发生读就需事件的时候,事件分离器调用第一步注册的事件处理器
4. 事件处理器首先执行实际的读取操做,而后根据读取到的内容进行进一步的处理
写入操做相似于读取操做,只不过第一步注册的是写就绪事件。
下面咱们来看看Proactor模式中读取操做和写入操做的过程:
读取操做:
1. 应用程序初始化一个异步读取操做,而后注册相应的事件处理器,此时事件处理器不关注读取就绪事件,而是关注读取完成事件,这是区别于Reactor的关键。
2. 事件分离器等待读取操做完成事件
3. 在事件分离器等待读取操做完成的时候,操做系统调用内核线程完成读取操做,并将读取的内容放入用户传递过来的缓存区中。这也是区别于Reactor的一点,Proactor中,应用程序须要传递缓存区。
4. 事件分离器捕获到读取完成事件后,激活应用程序注册的事件处理器,事件处理器直接从缓存区读取数据,而不须要进行实际的读取操做。
Proactor中写入操做和读取操做,只不过感兴趣的事件是写入完成事件。
从上面能够看出,Reactor和Proactor模式的主要区别就是真正的读取和写入操做是有谁来完成的,Reactor中须要应用程序本身读取或者写入数据,而Proactor模式中,应用程序不须要进行实际的读写过程,它只须要从缓存区读取或者写入便可,操做系统会读取缓存区或者写入缓存区到真正的IO设备.
综上所述,同步和异步是相对于应用和内核的交互方式而言的,同步 须要主动去询问,而异步的时候内核在IO事件发生的时候通知应用程序,而阻塞和非阻塞仅仅是系统在调用系统调用的时候函数的实现方式而已。
另外附一个总结的连接:http://blog.csdn.net/caiwenfeng_for_23/article/details/8458299
下面这个总结的很好:http://www.cnblogs.com/daoluanxiaozi/p/3274925.html
还有下面几个文章:
http://www.cnblogs.com/pigerhan/p/3474217.html
http://www.2cto.com/kf/201504/395318.html
http://blog.jobbole.com/59676/
http://cshbbrain.iteye.com/blog/1706269
http://www.cppblog.com/kevinlynx/archive/2008/06/06/52356.html