精华内容
下载资源
问答
  • Reactor和proactor模式

    2019-04-08 11:50:45
    两种高效的事件处理模式 前言 网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这被 称为C10K问题。C10K问题最早提出于2003年,10多年间,随着互联网的迅速发展,越来越多的网络服务面临的...

    两种高效的事件处理模式

    前言

          网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这被 称为 C10K 问题。C10K问题最早提出于2003年,10多年间,随着互联网的迅速发展,越来越多的网络服务面临的不再是C10K问题,而是C10M问题!

    典型的多线程服务器的线程模型

          最开始的网络编程服务器是用一个while循环来监听新的套接字连接,然后用一个函数处理。这种方法无法并发,效率太低。如果当前请求没有处理完,那后面的只能被阻塞,服务器的吞吐量太低。于是后来采用多线程:

          1. 每个请求创建一个线程,使用阻塞式 I/O 操作

          这是最简单的线程模型,1个线程处理1个连接的全部生命周期。该模型的优点在于:这个模型足够简单,它可以实现复杂的业务场景,同时,线程个数是可以远大于CPU个数的。然而,线程个数又不是可以无限增大的,为什么呢?因为线程什么时候执行是由操作系统内核调度算法决定的,调度算法并不会考虑某个线程可能只是为了一个连接服务的,时间片到了就执行一下,哪怕这个线程刚执行一会就又不得不继续睡眠。这样来回的唤醒、睡眠线程在次数不多的情况下,是廉价的,但如果操作系统的线程总数很多时,它就是昂贵的(被放大了),因为这种技术性的调度损耗会影响到线程上执行的业务代码的时间。举个例子,当我们所追求的是并发处理数十万连接,当几千个线程出现时,系统的执行效率就已经无法满足高并发了。换言之,该模型的扩展性及其糟糕,根本无法有效满足高并发,海量连接的业务场景。

          2. 使用线程池,同样使用阻塞式 I/O 操作

          这是针对模型1的改进,但仍未从根本上解决问题

          3. 使用非阻塞I/O + I/O复用

          4. Leader/Follower 等高级模式  

    两种高效的事件处理模式

      对高并发编程,目前只有一种模型,也是本质上唯一有效的玩法。网络连接上的消息处理,可以分为两个阶段:等待消息准备好、消息处理。当使用默认的阻塞套接字时(例如上面提到的1个线程捆绑处理1个连接),往往是把这两个阶段合而为一,这样操作套接字的代码所在的线程就得睡眠来等待消息准备好,这导致了高并发下线程会频繁的睡眠、唤醒,从而影响了CPU的使用效率。

          高并发编程方法当然就是把两个阶段分开处理即,等待消息准备好的代码段,与处理消息的代码段是分离的。当然,这也要求套接字必须是非阻塞的,否则,处理消息的代码段很容易导致条件不满足时,所在线程又进入了睡眠等待阶段。那么问题来了,等待消息准备好这个阶段怎么实现?它毕竟还是等待,这意味着线程还是要睡眠的!解决办法就是,线程主动查询,或者让1个线程为所有连接而等待!这就是IO多路复用了。多路复用就是处理等待消息准备好这件事的,但它可以同时处理多个连接!它也可能“等待”,所以它也会导致线程睡眠,然而这不要紧,因为它一对多、它可以监控所有连接。这样,当我们的线程被唤醒执行时,就一定是有一些连接已经准备好被我们的代码执行了。

          作为一个高性能服务器程序通常需要考虑处理三类事件: I/O事件,定时事件及信号。本文将首先首先从整体上介绍两种高校的事件处理模型:Reactor和Proactor。

    Reactor模型

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

        图 1. Reactor模型类图

    Reactor模式是处理并发I/O比较常见的一种模式,中心思想就是,将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程阻塞在多路复用器上;一旦有I/O事件到来或是准备就绪(区别在于多路复用器是边沿触发还是水平触发),多路复用器返回并将相应I/O事件分发到对应的处理器中

          Reactor模型有三个重要的组件:

    1. 多路复用器:由操作系统提供,在linux上一般是select, poll, epoll等系统调用。
    2. 事件分发器:将多路复用器中返回的就绪事件分到对应的处理函数中。
    3. 事件处理器:负责处理特定事件的处理函数。

          图 2. Reactor事件处理机制

          

         具体流程如下:

         1.  注册读就绪事件和相应的事件处理器; 
         2.  事件分离器等待事件; 
         3.  事件到来,激活分离器,分离器调用事件对应的处理器; 
         4.  事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。

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

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

          Reactor模型开发效率上比起直接使用IO复用要高,它通常是单线程的,设计目标是希望单线程使用一颗CPU的全部资源,但也有附带优点,即每个事件处理中很多时候可以不考虑共享资源的互斥访问。可是缺点也是明显的,现在的硬件发展,已经不再遵循摩尔定律,CPU的频率受制于材料的限制不再有大的提升,而改为是从核数的增加上提升能力,当程序需要使用多核资源时,Reactor模型就会悲剧, 为什么呢?

         如果程序业务很简单,例如只是简单的访问一些提供了并发访问的服务,就可以直接开启多个反应堆,每个反应堆对应一颗CPU核心,这些反应堆上跑的请求互不相关,这是完全可以利用多核的。例如Nginx这样的http静态服务器。

         如果程序比较复杂,例如一块内存数据的处理希望由多核共同完成,这样反应堆模型就很难做到了,需要昂贵的代价,引入许多复杂的机制。

    Proactor模型

          图 3. Proactor UML类图

          图 4. Proactor模型流程图

          

          具体流程如下:

    1.  处理器发起异步操作,并关注I/O完成事件
    2.  事件分离器等待操作完成事件
    3.  分离器等待过程中,内核并行执行实际的I/O操作,并将结果数据存入用户自定义缓冲区,最后通知事件分离器读操作完成
    4.  I/O完成后,通过事件分离器呼唤处理器
    5. 事件处理器处理用户自定义缓冲区中的数据

          从上面的处理流程,我们可以发现proactor模型最大的特点就是Proactor最大的特点是使用异步I/O。所有的I/O操作都交由系统提供的异步I/O接口去执行。工作线程仅仅负责业务逻辑。在Proactor中,用户函数启动一个异步的文件操作。同时将这个操作注册到多路复用器上。多路复用器并不关心文件是否可读或可写而是关心这个异步读操作是否完成。异步操作是操作系统完成,用户程序不需要关心。多路复用器等待直到有完成通知到来。当操作系统完成了读文件操作——将读到的数据复制到了用户先前提供的缓冲区之后,通知多路复用器相关操作已完成。多路复用器再调用相应的处理程序,处理数据。

          Proactor增加了编程的复杂度,但给工作线程带来了更高的效率。Proactor可以在系统态将读写优化,利用I/O并行能力,提供一个高性能单线程模型。在windows上,由于没有epoll这样的机制,因此提供了IOCP来支持高并发, 由于操作系统做了较好的优化,windows较常采用Proactor的模型利用完成端口来实现服务器。在linux上,在2.6内核出现了aio接口,但aio实际效果并不理想,它的出现,主要是解决poll性能不佳的问题,但实际上经过测试,epoll的性能高于poll+aio,并且aio不能处理accept,因此linux主要还是以Reactor模型为主。

          在不使用操作系统提供的异步I/O接口的情况下,还可以使用Reactor来模拟Proactor,差别是:使用异步接口可以利用系统提供的读写并行能力,而在模拟的情况下,这需要在用户态实现。具体的做法只需要这样:

    1. 注册读事件(同时再提供一段缓冲区)
    2. 事件分离器等待可读事件
    3. 事件到来,激活分离器,分离器(立即读数据,写缓冲区)调用事件处理器
    4. 事件处理器处理数据,删除事件(需要再用异步接口注册)     

          我们知道,Boost.asio库采用的即为Proactor模型。不过Boost.asio库在Linux平台采用epoll实现的Reactor来模拟Proactor,并且另外开了一个线程来完成读写调度。

          在《Linux高性能服务器编程》一书中(PS:一本好书,推荐购买阅读!)为我们提供一种精妙的设计思路:

            图 5. 使用同步I/O模拟Proactor模型

          

         

    1. 主线程往epoll内核事件表中注册socket上的读就绪事件。
    2. 主线程调用epoll_wait等待socket上有数据可读。
    3. 当socket上有数据可读时,epoll_wait通知主线程。主线程从socket循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成一个请求对象并插入请求队列。
    4. 睡眠在请求队列上的某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往epoll内核事件表中注册socket上的写就绪事件。
    5. 主线程调用epoll_wait等待socket可写。
    6. 当socket可写时,epoll_wait通知主线程。主线程往socket上写入服务器处理客户请求的结果。

    总结

          两个模式的相同点,都是对某个IO事件的事件通知(即告诉某个模块,这个IO操作可以进行或已经完成)。在结构上两者也有相同点:demultiplexor负责提交IO操作(异步)、查询设备是否可操作(同步),然后当条件满足时,就回调注册处理函数。

          不同点在于,异步情况下(Proactor),当回调注册的处理函数时,表示IO操作已经完成;同步情况下(Reactor),回调注册的处理函数时,表示IO设备可以进行某个操作(can read or can write),注册的处理函数这个时候开始提交操作。

          至于两种模式孰优孰劣的问题,笔者以为差异并不是特别大。两种模式的设计思想均足以很好的胜任高并发,海量连接的应用要求。当然,就目前笔者有限的了解,Reactor的应用实例还是更多一些,尤其是在Linux平台下。

          笔者水平有限,疏谬之处,万望斧正!

    以上参考:https://www.cnblogs.com/lojunren/p/3852514.html

    最后贴两张图加强理解,参考:https://blog.csdn.net/caiwenfeng_for_23/article/details/8458299 

    展开全文
  • Reactor和Proactor模式

    2020-09-27 08:11:57
    1.Reactor和Proactor模式的比较 两种I/O多路复用模式:Reactor和Proactor。一般地,I/O多路复用机制都依赖于一个事件多路分离器(Event Demultiplexer)。分离器可将来自事件源的I/O事件分离出来,并分发到对应的read/...

    1.Reactor和Proactor模式的比较

    两种I/O多路复用模式:Reactor和Proactor。一般地,I/O多路复用机制都依赖于一个事件多路分离器(Event Demultiplexer)。分离器可将来自事件源的I/O事件分离出来,并分发到对应的read/write事件处理器(Event Handler)。开发人员需预先注册需要处理的事件及其事件处理器(或回调函数);事件分离器负责将请求事件传递给事件处理器。

    两个与事件分离器有关的模式是Reactor和Proactor。Reactor模式采用同步IO,而Proactor采用异步IO。

    在Reactor中,事件分离器负责等待文件描述符或socket为读写操作准备就绪,然后将就绪事件传递给对应的处理器,最后由处理器负责完成实际的读写工作。

    而在Proactor模式中,处理器--或者兼任处理器的事件分离器,只负责发起异步读写操作。IO操作本身由操作系统来完成。传递给操作系统的参数需要包括用户定义的数据缓冲区地址和数据大小,操作系统才能从中得到写出操作所需数据,或写入从socket读到的数据。事件分离器捕获IO操作完成事件,然后将事件传递给对应处理器。

    以上的差异确定了两者不同的应用场景。Reactor框架中用户定义的操作是在实际操作之前调用的。比如你定义了操作是要向一个SOCKET写数据,那么当该SOCKET可以接收数据的时候,你的操作就会被调用;而Proactor框架中用户定义的操作是在实际操作之后调用的。比如你定义了一个操作要显示从SOCKET中读入的数据,那么当读操作完成以后,你的操作才会被调用。

    Proactor和Reactor都是并发编程中的设计模式,都是用于派发/分离IO操作事件的。这里所谓的IO事件也就是诸如read/write的IO操作。"派发/分离"就是将单独的IO事件通知到上层模块。两个模式不同的地方在于,Proactor用于异步IO,而Reactor用于同步IO。

    2.Proactor模式详细介绍

    proactor模式的整体结构图如下:

     整体流程如下:

    (1)为了异步式的执行服务,作为客户端的应用程序将异步操作传递给异步操作处理器以完成初始化操作。同时,客户端需向异步操作处理器指明异步操作完成后回调哪个完成句柄执行后续的工作。(注册回调函数)

    (2)客户端在异步操作处理器激活操作之后,操作和客户端可以和其他应用程序激活的异步操作一起并行的运行。

    (3)当操作执行完后,异步操作处理器取回操作初始化时客户端限定的完成句柄和proactor。然后异步操作处理器传递异步操作的结果和完成句柄给proactor,由其完成分发。

    (4)proactor分发完成句柄的钩子方法,并传递完成数据。

    详细的处理过程如下:

     

    展开全文
  • reactor和proactor模式

    万次阅读 多人点赞 2013-01-02 08:11:25
    首先分享一下,我在网上看到的两篇不错的文章:正是这两篇文章才理解了reactor和proactor模式;  Reactor模式,或者叫反应器模式 高性能IO设计的Reactor和Proactor模式  首先就第一篇《Reactor模式,或者叫...

    首先分享一下,我在网上看到的两篇不错的文章:正是这两篇文章才理解了reactor和proactor模式;

     Reactor模式,或者叫反应器模式

    高性能IO设计的Reactor和Proactor模式

     首先就第一篇《Reactor模式,或者叫反应器模式》做一下笔记:

     

    刚开店做生意,老板为了给顾客一个美好的印象,给顾客最好的服务,一对一:

     

    随着经营的生意越来越好,顾客多了,不能服务员也多吧,那样得支出的成本也太大了,要是一下子来个1000个顾客,难道老板还得养活1000个服务员,没办法,得改变这种服务模式,但又不能让顾客感到这里的服务下降了,怎么办呢?

     

    改革以后,有没有觉得和我们平时去大排档啊,街边小吃店的服务模式很相似是不是,

    为什么不说和酒店服务很像,其实还真不像,一般XXX星级的饭店的服务,还真是上一种经营模式,为什么他们要这样呢,

    因为,他们是高富帅啊,顾客消费也高,自然老板的收入也高,所以老板也乐子不疲啊。我们是屌丝,请客都只是去个大排档就好了。

     

    改革后的模式就是reactor模式,顾客通过呼叫服务员(event事件)通知服务员,菜单写好了,服务员就会把菜单交给厨师(事件处理器),厨师就会去做菜了。

     

     

    现在知道reactor模式的由来了吧,知道一个事情的始末会让我们更好的理解它。

    下面对第二篇《高性能IO设计的Reactor和Proactor模式》做一下笔记:

    这里主要是讲reactor模式和proactor模式的区别:其实就是对数据处理方式变了导致监听事件方式也转变了。

    当然,如果还是以第一篇那样以饭店的经营模式来讲解的话,proactor模式应该是这样的:

     

    我们知道每一个饭店都有自己的招牌菜去吸引顾客。当然,其实这道菜你也会做,只是别人做的比你更好,更美味。有一天,一群高富帅来了这家大拍档:

     

     

    老板就是老板,人面广啊,自家厨师不会做,可以让更专业的人去做,省时省事省心啊!

     

    其实这里我们都能看出reactor模式和proactor模式的一点点区别了吧!只是还不了解具体的细节。

    第二篇《性能IO设计的Reactor和Proactor模式》就是干这个事的,给我们介绍具体细节和区别,我也是读了好几遍,慢慢画个流程图才理解了啊。

    其实说到底就是一句广告语:把事情交给更专业的人,你会更开心。

     

    好吧,以下是copy过来,做了少少修改的:转换为自己的理解

            

     

           在高性能的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事件发生的时候通知应用程序,而阻塞和非阻塞仅仅是系统在调用系统调用的时候函数的实现方式而已。

     

    最后来两张图做个总结:

     

    展开全文
  • reactor proactor 模式

    2020-04-03 12:13:27
    高性能 IO 设计的 Reactor Proactor 模式 首先就第一篇《Reactor 模式,或者叫反应器模式》做一下笔记: 刚开店做生意,老板为了给顾客一个美好的印象,给顾客最好的服务,一对一: 正在上传…重新上传取消 ...

     

    首先分享一下,我在网上看到的两篇不错的文章:正是这两篇文章才理解了 reactor 和 pr oactor 模式;

    Reactor 模式,或者叫反应器模式
    高性能 IO 设计的 Reactor 和 Proactor 模式

    首先就第一篇《Reactor 模式,或者叫反应器模式》做一下笔记:

    刚开店做生意,老板为了给顾客一个美好的印象,给顾客最好的服务,一对一:

    uploading.4e448015.gif正在上传…重新上传取消

    uploading.4e448015.gif正在上传…重新上传取消

    随着经营的生意越来越好,顾客多了,不能服务员也多吧,那样得支出的成本也太大了,要 是一下子来个 1000 个顾客,难道老板还得养活 1000 个服务员,没办法,得改变这种服务 模式,但又不能让顾客感到这里的服务下降了,怎么办呢?

    uploading.4e448015.gif正在上传…重新上传取消

    改革以后,有没有觉得和我们平时去大排档啊,街边小吃店的服务模式很相似是不是,

    为什么不说和酒店服务很像,其实还真不像,一般 XXX 星级的饭店的服务,还真是上一种 经营模式,为什么他们要这样呢,

    因为,他们是高富帅啊,顾客消费也高,自然老板的收入也高,所以老板也乐子不疲啊。我 们是屌丝,请客都只是去个大排档就好了。

    改革后的模式就是 reactor 模式,顾客通过呼叫服务员(event 事件)通知服务员,菜单写 好了,服务员就会把菜单交给厨师(事件处理器),厨师就会去做菜了。

    现在知道 reactor 模式的由来了吧,知道一个事情的始末会让我们更好的理解它。

    下面对第二篇《高性能 IO 设计的 Reactor 和 Proactor 模式》做一下笔记:

    这里主要是讲 reactor 模式和 proactor 模式的区别:其实就是对数据处理方式变了导致监 听事件方式也转变了。

    当然,如果还是以第一篇那样以饭店的经营模式来讲解的话,proactor 模式应该是这样的:

    我们知道每一个饭店都有自己的招牌菜去吸引顾客。当然,其实这道菜你也会做,只是别人 做的比你更好,更美味。有一天,一群高富帅来了这家大拍档:

    uploading.4e448015.gif正在上传…重新上传取消

    老板就是老板,人面广啊,自家厨师不会做,可以让更专业的人去做,省时省事省心啊!

    其实这里我们都能看出 reactor 模式和 proactor 模式的一点点区别了吧!只是还不了解具 体的细节。

    第二篇《性能 IO 设计的 Reactor 和 Proactor 模式》就是干这个事的,给我们介绍具体细 节和区别,我也是读了好几遍,慢慢画个流程图才理解了啊。

    其实说到底就是一句广告语:把事情交给更专业的人,你会更开心。

    好吧,以下是 copy 过来,做了少少修改的:转换为自己的理解。

    在高性能的 I/O 设计中,有两个比较著名的模式 Reactor 和 Proactor 模式,其中 Re actor 模式用于同步 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 中需要应用程序自己读取或者写入数据,而 Pro actor 模式中,应用程序不需要进行实际的读写过程,它只需要从缓存区读取或 者写入即可,操作系统会读取缓存区或者写入缓存区到真正的 IO 设备.

    综上所述,同步和异步是相对于应用和内核的交互方式而言的,同步 需要主动 去询问,而异步的时候内核在 IO 事件发生的时候通知应用程序,而阻塞和非阻 塞仅仅是系统在调用系统调用的时候函数的实现方式而已。



    正在上传…重新上传取消

    展开全文
  • 8、IO设计模式Reactor和Proactor 8.1 反应器Reactor模式 8.1.1 概述 反应器模式Reactor Pattern)是一种为处理并发服务请求并将请求提交到一个或者多个服务处理程序的事件设计模式。当客户端请求到达时,...
  • Reactor和Proactor模式比较

    千次阅读 2014-11-27 16:44:08
    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作。 在比较这两个模式之前,我们首先的搞明白几个概念,什么是阻塞非阻塞,什么是...
  • http://xmuzyq.iteye.com/blog/783218
  • 1、Reactor模式(同步I/O模型通常用于实现Reactor模式) 它要求主线程(I/O处理单元,下同)只负责监听文件描述符上是否有事件发生,有的话就立刻将该事件通知工作线程。除此之外,主线程不做任何其他实质性的工作...
  • 1.先解释同步异步: 同步异步是一种通信机制。 同步:调用方需要保持等待直到I/O操作完成。 异步:调用方可以不用保持等待,只需要操作系统完成I/O操作通知调用方就可以了。 2.再说说阻塞非阻塞: 阻塞非...
  • reactor和proactor模式(epolliocp)

    千次阅读 2014-08-19 18:55:52
    首先分享一下,我在网上看到的两篇不错的文章:正是这两篇文章才理解了reactor和proactor模式;  Reactor模式,或者叫反应器模式 高性能IO设计的Reactor和Proactor模式  首先就第一篇《Reactor模式,或者...
  • 本人学习ACE 时候写的关于两种通信方式的实例代码,我把三个连写都写在了一个文件,根据需要注释掉其他的就行。 ACE用于开发通信程序非常方便,尤其相对于WinSock 来说,可以省很多代码,普通程序员也更容易理解
  • ACE proactorReactor 模式的详解

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,967
精华内容 1,986
关键字:

reactor和proactor模式