Reactor和Proactor模式

首先分享一下,我在網上看到的兩篇不錯的文章:正是這兩篇文章才理解了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事件發生的時候通知應用程序,而阻塞和非阻塞僅僅是系統在調用系統調用的時候函數的實現方式而已。

 

最後來兩張圖做個總結:

 


IO設計模式:Reactor和Proactor對比

平時接觸的開源產品如Redis、ACE,事件模型都使用的Reactor模式;而同樣做事件處理的Proactor,由於操作系統的原因,相關的開源產品也少;這裏學習下其模型結構,重點對比下兩者的異同點;

反應器Reactor

Reactor模式結構

Reactor

Reactor包含如下角色:

  • Handle 句柄;用來標識socket連接或是打開文件;
  • Synchronous Event Demultiplexer:同步事件多路分解器:由操作系統內核實現的一個函數;用於阻塞等待發生在句柄集合上的一個或多個事件;(如select/epoll;)
  • Event Handler:事件處理接口
  • Concrete Event HandlerA:實現應用程序所提供的特定事件處理邏輯;
  • Reactor:反應器,定義一個接口,實現以下功能: 
    1)供應用程序註冊和刪除關注的事件句柄; 
    2)運行事件循環; 
    3)有就緒事件到來時,分發事件到之前註冊的回調函數上處理;

 

“反應”器名字中”反應“的由來: 
“反應”即“倒置”,“控制逆轉”,具體事件處理程序不調用反應器,而是由反應器分配一個具體事件處理程序,具體事件處理程序對某個指定的事件發生做出反應;這種控制逆轉又稱爲“好萊塢法則”(不要調用我,讓我來調用你)

業務流程及時序圖

seq_Reactor

  1. 應用啓動,將關注的事件handle註冊到Reactor中;
  2. 調用Reactor,進入無限事件循環,等待註冊的事件到來;
  3. 事件到來,select返回,Reactor將事件分發到之前註冊的回調函數中處理;

主動器Proactor

Proactor模式結構

Proactor

Proactor主動器模式包含如下角色

  • Handle 句柄;用來標識socket連接或是打開文件;
  • Asynchronous Operation Processor:異步操作處理器;負責執行異步操作,一般由操作系統內核實現;
  • Asynchronous Operation:異步操作
  • Completion Event Queue:完成事件隊列;異步操作完成的結果放到隊列中等待後續使用
  • Proactor:主動器;爲應用程序進程提供事件循環;從完成事件隊列中取出異步操作的結果,分發調用相應的後續處理邏輯;
  • Completion Handler:完成事件接口;一般是由回調函數組成的接口;
  • Concrete Completion Handler:完成事件處理邏輯;實現接口定義特定的應用處理邏輯;

業務流程及時序圖

seq_Proactor

  1. 應用程序啓動,調用異步操作處理器提供的異步操作接口函數,調用之後應用程序和異步操作處理就獨立運行;應用程序可以調用新的異步操作,而其它操作可以併發進行;
  2. 應用程序啓動Proactor主動器,進行無限的事件循環,等待完成事件到來;
  3. 異步操作處理器執行異步操作,完成後將結果放入到完成事件隊列;
  4. 主動器從完成事件隊列中取出結果,分發到相應的完成事件回調函數處理邏輯中;

對比兩者的區別

主動和被動

以主動寫爲例: 
Reactor將handle放到select(),等待可寫就緒,然後調用write()寫入數據;寫完處理後續邏輯; 
Proactor調用aoi_write後立刻返回,由內核負責寫操作,寫完後調用相應的回調函數處理後續邏輯;

可以看出,Reactor被動的等待指示事件的到來並做出反應;它有一個等待的過程,做什麼都要先放入到監聽事件集合中等待handler可用時再進行操作; 
Proactor直接調用異步讀寫操作,調用完後立刻返回;

實現

Reactor實現了一個被動的事件分離和分發模型,服務等待請求事件的到來,再通過不受間斷的同步處理事件,從而做出反應;

Proactor實現了一個主動的事件分離和分發模型;這種設計允許多個任務併發的執行,從而提高吞吐量;並可執行耗時長的任務(各個任務間互不影響)

優點

Reactor實現相對簡單,對於耗時短的處理場景處理高效; 
操作系統可以在多個事件源上等待,並且避免了多線程編程相關的性能開銷和編程複雜性; 
事件的串行化對應用是透明的,可以順序的同步執行而不需要加鎖; 
事務分離:將與應用無關的多路分解和分配機制和與應用相關的回調函數分離開來,

Proactor性能更高,能夠處理耗時長的併發場景;

缺點

Reactor處理耗時長的操作會造成事件分發的阻塞,影響到後續事件的處理;

Proactor實現邏輯複雜;依賴操作系統對異步的支持,目前實現了純異步操作的操作系統少,實現優秀的如windows IOCP,但由於其windows系統用於服務器的侷限性,目前應用範圍較小;而Unix/Linux系統對純異步的支持有限,應用事件驅動的主流還是通過select/epoll來實現;

適用場景

Reactor:同時接收多個服務請求,並且依次同步的處理它們的事件驅動程序; 
Proactor:異步接收和同時處理多個服務請求的事件驅動程序;

轉載:

http://blog.csdn.net/caiwenfeng_for_23/article/details/8458299

http://www.cnblogs.com/me115/p/4452801.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章