Reactor 和 Proactor 是基於事件驅動,在網絡編程中常常用到兩種設計模式。html
曾經在一個項目中用到了網絡庫 libevent,也學習了一段時間,其內部實現所用到的就是 Reactor,所知道的還有 ACE;Proactor 模式的庫有 Boost.Asio,ACE,暫時沒有用過。但我也翻閱了一些文檔,理解了它的實現方法。下面是我在學習這兩種設計模式過程的筆記。react
Reactor,即反應堆。Reactor 的通常工做過程是首先在 Reactor 中註冊(Reactor)感興趣事件,並在註冊時候指定某個已定義的回調函數(callback);當客戶端發送請求時,在 Reactor 中會觸發剛纔註冊的事件,並調用對應的處理函數。在這一個處理回調函數中,通常會有數據接收、處理、回覆請求等操做。web
libevent 採用的就是 Reactor 的設計思想。其 Reactor 的中心思想是衆所周知的 I/O 多路複用:select,poll,epoll,kqueue 等.libevent 精彩的將定時事件,信號處理,I/O 事件結合在在一塊兒,也就是說用戶同時在 Reactor 中註冊上述三類事件。遺憾的是,libevent 不支持多線程,也就是說它同步處理請求,致使不能處理大量的請求;這樣並非說 Reactor 實現的網絡庫都不支持多線程,而是 libevent 自己的緣由,咱們也能夠經過修改讓 ilbevent 支持多線程,併發處理多個請求。編程
下面是 libevent 的一段代碼,大概可以說明 Reactor 工做模式:設計模式
/*accept callback function.*/ void accept_callback(int fd, short ev,void *arg) { ...... } ...... struct event accept_event; event_set(&accept_event, socketlisten, EV_READ|EV_PERSIST, accept_callback, NULL); event_add(&accept_event, NULL); event_dispatch();
從上面 Reactor 模式中,發現服務端數據的接收和發送都佔用了用戶狀態(還有一種內核態),這樣服務器的處理操做就在數據的讀寫上阻塞花費了時間,節省這些時間的辦法是藉助操做系統的異步讀寫;異步讀寫在調用的時候能夠傳遞迴調函數或者回送信號,當異步操做完畢,內核會自動調用回調函數或者發送信號。Proactor 就是這麼作的,因此很依賴操做系統。來一幅 UML:瀏覽器
和時序圖:服務器
注:這兩幅美豔的圖片來自 Proactor.doc,下面會提到.網絡
Proactor 的實現主要有三個部分:異步操做處理器,Proactor 和 事件處理函數。其中:多線程
- 異步操做處理器,很依賴操做系統的異步處理機制,如若操做系統沒有實現,咱們能夠自行模擬,即開專門的數據讀寫線程,數據讀寫完畢觸發相應的時間(若是有註冊的話); - Proactor,會接收異步操做的提醒,調用相應的事件處理函數,它有本身的 event loop; - 事件處理函數,事件觸發,執行操做;
曾經看過 Proactor.doc,做者是 Douglas C. Schmidt,你能夠在這裏閱讀此文檔。裏面的關於 Proactor 的講解很精彩,部分摘抄和本身的理解以下:當鏈接 web 服務器時:併發
接收 GET 請求事後,會處理數據:
相比網絡編程中最簡單的思路模式:bind,listen,accept,read,server operator,write,Reactor 和 Proactor 是兩種高性能的設計模式,掌握此兩種模式,有助於理解一些網絡庫的工做流程。此文提到了兩種設計模式,但沒有一些技術細節,譬如多線程同步。若是在 Reactor 中支持多線程,或多個線程共享一個 Proactor,線程的同步問題就來了。共享一篇印象筆記關於線程的綜合討論:這裏.
《Comparing Two High-Performance I/O Design Patterns》提到一個將 Reactor 模擬 Proactor 而不借助操做系統異步機制的方法:一樣在 Reactor 註冊感興趣的事件(好比讀),當事件發生時,執行非阻塞的讀,讀畢即才調用數據處理——假異步。
最後,實踐出真知。歡迎討論。
參考:
- Proactor.pdf,http://www.laputan.org/pub/sag/proactor.pdf
- 《Comparing Two High-Performance I/O Design Patterns》,http://www.artima.com/articles/io_design_patterns.html
- 《libevent源碼深度剖析》,http://blog.csdn.net/sparkliang/article/details/4957667
- 《 IO - 同步,異步,阻塞,非阻塞 (亡羊補牢篇)》,http://blog.csdn.net/historyasamirror/article/details/5778378
搗亂 2013-08-21