該文章總結了網上資源對這兩種模式的描述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