小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

兩種高性能 I/O 設(shè)計模式 Reactor 和 Proactor

 流曲頻陽 2016-11-02

Reactor 和 Proactor 是基于事件驅(qū)動,在網(wǎng)絡編程中經(jīng)常用到兩種設(shè)計模式。

曾經(jīng)在一個項目中用到了網(wǎng)絡庫 libevent,也學習了一段時間,其內(nèi)部實現(xiàn)所用到的就是 Reactor,所知道的還有 ACE;Proactor 模式的庫有 Boost.Asio,ACE,暫時沒有用過。但我也翻閱了一些文檔,理解了它的實現(xiàn)方法。下面是我在學習這兩種設(shè)計模式過程的筆記。

Reactor

Reactor,即反應堆。Reactor 的一般工作過程是首先在 Reactor 中注冊(Reactor)感興趣事件,并在注冊時候指定某個已定義的回調(diào)函數(shù)(callback);當客戶端發(fā)送請求時,在 Reactor 中會觸發(fā)剛才注冊的事件,并調(diào)用對應的處理函數(shù)。在這一個處理回調(diào)函數(shù)中,一般會有數(shù)據(jù)接收、處理、回復請求等操作。

libevent 采用的就是 Reactor 的設(shè)計思想。其 Reactor 的中心思想是眾所周知的 I/O 多路復用:select,poll,epoll,kqueue 等.libevent 精彩的將定時事件,信號處理,I/O 事件結(jié)合在在一起,也就是說用戶同時在 Reactor 中注冊上述三類事件。遺憾的是,libevent 不支持多線程,也就是說它同步處理請求,導致不能處理大量的請求;這樣并不是說 Reactor 實現(xiàn)的網(wǎng)絡庫都不支持多線程,而是 libevent 本身的原因,我們也可以通過修改讓 ilbevent 支持多線程,并發(fā)處理多個請求。

下面是 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();

Proactor

從上面 Reactor 模式中,發(fā)現(xiàn)服務端數(shù)據(jù)的接收和發(fā)送都占用了用戶狀態(tài)(還有一種內(nèi)核態(tài)),這樣服務器的處理操作就在數(shù)據(jù)的讀寫上阻塞花費了時間,節(jié)省這些時間的辦法是借助操作系統(tǒng)的異步讀寫;異步讀寫在調(diào)用的時候可以傳遞回調(diào)函數(shù)或者回送信號,當異步操作完畢,內(nèi)核會自動調(diào)用回調(diào)函數(shù)或者發(fā)送信號。Proactor 就是這么做的,所以很依賴操作系統(tǒng)。來一幅 UML:

和時序圖:

注:這兩幅美艷的圖片來自 Proactor.doc,下面會提到.

Proactor 的實現(xiàn)主要有三個部分:異步操作處理器,Proactor 和 事件處理函數(shù)。其中:

- 異步操作處理器,很依賴操作系統(tǒng)的異步處理機制,如若操作系統(tǒng)沒有實現(xiàn),我們可以自行模擬,即開專門的數(shù)據(jù)讀寫線程,數(shù)據(jù)讀寫完畢觸發(fā)相應的時間(如果有注冊的話);
- Proactor,會接收異步操作的提醒,調(diào)用相應的事件處理函數(shù),它有自己的 event loop;
- 事件處理函數(shù),事件觸發(fā),執(zhí)行操作;

曾經(jīng)看過 Proactor.doc,作者是 Douglas C. Schmidt,你可以在這里閱讀此文檔。里面的關(guān)于 Proactor 的講解很精彩,部分摘抄和自己的理解如下:當連接 web 服務器時:

  • web 服務器指定(1)接收器,此接收器相當于服務器的客戶端,它可以啟動異步的 accept 操作;

  • 接收器調(diào)用操作系統(tǒng)上的異步接收操作(2),并傳遞自己和 Proactor 的引用;異步接收操作結(jié)束后,前者用作事件處理函數(shù),后者會回過頭來分發(fā)事件;注:傳遞 Proactor 是為了讓操作系統(tǒng)通知正確的 Proactor,可能會存在多個 Proactor;傳遞接收器自己是為了在異步接收操作結(jié)束后 Proactor 能調(diào)用正確的事件處理函數(shù),以下同理。

  • web 服務器調(diào)用 Proactor 的事件循環(huán);(3)

  • web 瀏覽器連接 web 服務器;(4)

  • 異步接收操作結(jié)束后,操作系統(tǒng)產(chǎn)生事件(通過回調(diào)或者信號)并通知 Proactor(5),Proactor 收到后會調(diào)用相應的事件處理函數(shù),即交由接收器處理;(6)

  • 接收器生成 HTTP 處理器,執(zhí)行操作;(7)

  • HTTP 處理器解析事件,啟動異步讀操作(8),獲取來自瀏覽器的 GET 請求。同樣,HTTP 處理器傳遞自己和 Proactor 的引用;

  • web 服務器的控制權(quán)交還回 Proactor 的事件循環(huán)。(9)

接收 GET 請求過后,會處理數(shù)據(jù):

  • 瀏覽器發(fā)送(1)一個 HTTP GET 請求;

  • 異步讀操作結(jié)束后,操作系統(tǒng)會通知 Proactor,Proactor 分發(fā)給事件處理函數(shù);(2,3)

  • 事件處理器解析請求。(4)2-4 步驟會重復,指導所有的數(shù)據(jù)都接收為止;

  • 事件處理器產(chǎn)生答復數(shù)據(jù);(5)

  • HTTP 處理器啟動異步寫操作(6),傳輸應答數(shù)據(jù),同樣的這里還會傳遞處理器自己和 Proactor;

  • 異步寫操作結(jié)束,操作系統(tǒng)通知 Proactor(7),Proactor 分發(fā)給事件處理函數(shù)(8)。6-8 步驟會重復直到所有的數(shù)據(jù)寫完為止。至此,一個請求回復完成。

總結(jié)

相比網(wǎng)絡編程中最簡單的思路模式:bind,listen,accept,read,server operator,write,Reactor 和 Proactor 是兩種高性能的設(shè)計模式,掌握此兩種模式,有助于理解一些網(wǎng)絡庫的工作流程。此文提到了兩種設(shè)計模式,但沒有一些技術(shù)細節(jié),譬如多線程同步。如果在 Reactor 中支持多線程,或多個線程共享一個 Proactor,線程的同步問題就來了。共享一篇印象筆記關(guān)于線程的綜合討論:這里.

Comparing Two High-Performance I/O Design Patterns》提到一個將 Reactor 模擬 Proactor 而不借助操作系統(tǒng)異步機制的方法:同樣在 Reactor 注冊感興趣的事件(比如讀),當事件發(fā)生時,執(zhí)行非阻塞的讀,讀畢即才調(diào)用數(shù)據(jù)處理——假異步。

最后,實踐出真知。歡迎討論。

參考:

- Proactor.pdf,http://www./pub/sag/proactor.pdf

- 《Comparing Two High-Performance I/O Design Patterns》,http://www./articles/io_design_patterns.html

- 《libevent源碼深度剖析》,http://blog.csdn.net/sparkliang/article/details/4957667

- 《 IO - 同步,異步,阻塞,非阻塞 (亡羊補牢篇)》,http://blog.csdn.net/historyasamirror/article/details/5778378


    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多