高性能I/O设计模式Reactor和Proactor
昨天購(gòu)買(mǎi)了《程序員》雜志?2007.4期,第一時(shí)間去翻閱了一遍,其中有一篇《兩種高性能I/O設(shè)計(jì)模式的比較》令人眼睛一亮,這是一篇譯文,偶最近在一直想認(rèn)真看看這方面的文章很久了。
文章主要是講到了系統(tǒng)I/O方式可分為阻塞,非阻塞同步和非阻塞異步三類(lèi),三種方式中,非阻塞異步模式的擴(kuò)展性和性能最好。主要是講了兩種IO多路復(fù)用模式:Reactor和Proactor,并對(duì)它們進(jìn)行了比較。
文章還介紹了為Reactor和Proactor模式構(gòu)建一個(gè)通用的,統(tǒng)一的對(duì)外接口并是一個(gè)完全可移植的開(kāi)發(fā)框架選擇方案:TProactor(ACE compatible Proactor) :http://www.terabit.com.au/solutions.php。因?yàn)長(zhǎng)inux對(duì)aio支持的不完整,所以ACE_Proactor框架在linux上的表現(xiàn)很差,大部分在windows上執(zhí)行正常的代碼,在Linux則運(yùn)行異常,甚至不能編譯通過(guò)。這個(gè)問(wèn)題一直困擾著很大多數(shù)ACE的用戶(hù),現(xiàn)在好了,有一個(gè)TProactor幫助解決了在Linux不完整支持AIO的條件下,正常使用(至少是看起來(lái)正常)ACE_Proactor。
文章主要摘要:
---------->
兩種I/O多路復(fù)用模式:Reactor和Proactor
?一般地,I/O多路復(fù)用機(jī)制都依賴(lài)于一個(gè)事件多路分離器(Event Demultiplexer)。分離器對(duì)象可將來(lái)自事件源的I/O事件分離出來(lái),并分發(fā)到對(duì)應(yīng)的read/write事件處理器(Event Handler)。開(kāi)發(fā)人員預(yù)先注冊(cè)需要處理的事件及其事件處理器(或回調(diào)函數(shù));事件分離器負(fù)責(zé)將請(qǐng)求事件傳遞給事件處理器。兩個(gè)與事件分離器有關(guān)的模式是Reactor和Proactor。Reactor模式采用同步IO,而Proactor采用異步IO。
?在Reactor中,事件分離器負(fù)責(zé)等待文件描述符或socket為讀寫(xiě)操作準(zhǔn)備就緒,然后將就緒事件傳遞給對(duì)應(yīng)的處理器,最后由處理器負(fù)責(zé)完成實(shí)際的讀寫(xiě)工作。
?而在Proactor模式中,處理器--或者兼任處理器的事件分離器,只負(fù)責(zé)發(fā)起異步讀寫(xiě)操作。IO操作本身由操作系統(tǒng)來(lái)完成。傳遞給操作系統(tǒng)的參數(shù)需要包括用戶(hù)定義的數(shù)據(jù)緩沖區(qū)地址和數(shù)據(jù)大小,操作系統(tǒng)才能從中得到寫(xiě)出操作所需數(shù)據(jù),或?qū)懭霃膕ocket讀到的數(shù)據(jù)。事件分離器捕獲IO操作完成事件,然后將事件傳遞給對(duì)應(yīng)處理器。比如,在windows上,處理器發(fā)起一個(gè)異步IO操作,再由事件分離器等待IOCompletion事件。典型的異步模式實(shí)現(xiàn),都建立在操作系統(tǒng)支持異步API的基礎(chǔ)之上,我們將這種實(shí)現(xiàn)稱(chēng)為“系統(tǒng)級(jí)”異步或“真”異步,因?yàn)閼?yīng)用程序完全依賴(lài)操作系統(tǒng)執(zhí)行真正的IO工作。
?舉個(gè)例子,將有助于理解Reactor與Proactor二者的差異,以讀操作為例(類(lèi)操作類(lèi)似)。
?在Reactor中實(shí)現(xiàn)讀:
?- 注冊(cè)讀就緒事件和相應(yīng)的事件處理器
?- 事件分離器等待事件
?- 事件到來(lái),激活分離器,分離器調(diào)用事件對(duì)應(yīng)的處理器。
?- 事件處理器完成實(shí)際的讀操作,處理讀到的數(shù)據(jù),注冊(cè)新的事件,然后返還控制權(quán)。
?與如下Proactor(真異步)中的讀過(guò)程比較:
?- 處理器發(fā)起異步讀操作(注意:操作系統(tǒng)必須支持異步IO)。在這種情況下,處理器無(wú)視IO就緒事件,它關(guān)注的是完成事件。
?- 事件分離器等待操作完成事件
?- 在分離器等待過(guò)程中,操作系統(tǒng)利用并行的內(nèi)核線(xiàn)程執(zhí)行實(shí)際的讀操作,并將結(jié)果數(shù)據(jù)存入用戶(hù)自定義緩沖區(qū),最后通知事件分離器讀操作完成。
?- 事件分離器呼喚處理器。
?- 事件處理器處理用戶(hù)自定義緩沖區(qū)中的數(shù)據(jù),然后啟動(dòng)一個(gè)新的異步操作,并將控制權(quán)返回事件分離器。
?
實(shí)踐現(xiàn)狀?
?由Douglas Schmidt等人開(kāi)發(fā)的開(kāi)源C++開(kāi)發(fā)框架ACE,提供了大量與平臺(tái)無(wú)關(guān),支持并發(fā)的底層類(lèi)(線(xiàn)程,互斥量等),且在高抽象層次上,提供了兩組不同的類(lèi)--ACE Reactor和ACE Proactor的實(shí)現(xiàn)。不過(guò),雖然二者都與平臺(tái)無(wú)關(guān),提供的接口卻各異。
?ACE Proactor在windows平臺(tái)上具有更為優(yōu)異的性能表現(xiàn),因?yàn)閣indows在操作系統(tǒng)提供了高效的異步API支持(見(jiàn)http://msdn2.microsoft.com/en-us/library/aa365198.aspx)。
?然而,并非所有的操作系統(tǒng)都在系統(tǒng)級(jí)大力支持異步。像很多Unix系統(tǒng)就沒(méi)做到。因此,在Unix上,選擇ACE Reactor解決方案可能更好。但這樣一來(lái),為了獲得最好的性能,網(wǎng)絡(luò)應(yīng)用的開(kāi)發(fā)人員必須為不同的操作系統(tǒng)維護(hù)多份代碼:windows上以ACE Proactor為基礎(chǔ),而Unix系統(tǒng)上則采用ACE Reactor解決方案。
?
改進(jìn)方案
? 在這部分,我們將嘗試應(yīng)對(duì)為Proactor和Reactor模式建立可移植框架的挑戰(zhàn)。在改進(jìn)方案中,我們將Reactor原來(lái)位于事件處理器內(nèi)的read/write操作移至分離器(不妨將這個(gè)思路稱(chēng)為“模擬異步”),以此尋求將Reactor多路同步IO轉(zhuǎn)化為模擬異步IO。以讀操作為例子,改進(jìn)過(guò)程如下:
? - 注冊(cè)讀就緒事件及其處理器,并為分離器提供數(shù)據(jù)緩沖區(qū)地址,需要讀取數(shù)據(jù)量等信息。
? - 分離器等待事件(如在select()上等待)
? - 事件到來(lái),激活分離器。分離器執(zhí)行一個(gè)非阻塞讀操作(它有完成這個(gè)操作所需的全部信息),最后調(diào)用對(duì)應(yīng)處理器。
? - 事件處理器處理用戶(hù)自定義緩沖區(qū)的數(shù)據(jù),注冊(cè)新的事件(當(dāng)然同樣要給出數(shù)據(jù)緩沖區(qū)地址,需要讀取的數(shù)據(jù)量等信息),最后將控制權(quán)返還分離器。
? 如我們所見(jiàn),通過(guò)對(duì)多路IO模式功能結(jié)構(gòu)的改造,可將Reactor轉(zhuǎn)化為Proactor模式。改造前后,模型實(shí)際完成的工作量沒(méi)有增加,只不過(guò)參與者間對(duì)工作職責(zé)稍加調(diào)換。沒(méi)有工作量的改變,自然不會(huì)造成性能的削弱。對(duì)如下各步驟的比較,可以證明工作量的恒定:
? 標(biāo)準(zhǔn)/典型的Reactor:
? - 步驟1:等待事件到來(lái)(Reactor負(fù)責(zé))
? - 步驟2:將讀就緒事件分發(fā)給用戶(hù)定義的處理器(Reactor負(fù)責(zé))
? - 步驟3:讀數(shù)據(jù)(用戶(hù)處理器負(fù)責(zé))
? - 步驟4:處理數(shù)據(jù)(用戶(hù)處理器負(fù)責(zé))
? 改進(jìn)實(shí)現(xiàn)的模擬Proactor:
? - 步驟1:等待事件到來(lái)(Proactor負(fù)責(zé))
? - 步驟2:得到讀就緒事件,執(zhí)行讀數(shù)據(jù)(現(xiàn)在由Proactor負(fù)責(zé))
? - 步驟3:將讀完成事件分發(fā)給用戶(hù)處理器(Proactor負(fù)責(zé))
? - 步驟4:處理數(shù)據(jù)(用戶(hù)處理器負(fù)責(zé))?
?
? 對(duì)于不提供異步IO API的操作系統(tǒng)來(lái)說(shuō),這種辦法可以隱藏socket API的交互細(xì)節(jié),從而對(duì)外暴露一個(gè)完整的異步接口。借此,我們就可以進(jìn)一步構(gòu)建完全可移植的,平臺(tái)無(wú)關(guān)的,有通用對(duì)外接口的解決方案。
? ?
?上述方案已經(jīng)由Terabit P/L公司(http://www.terabit.com.au/)實(shí)現(xiàn)為T(mén)Proactor。它有兩個(gè)版本:C++和JAVA的。C++版本采用ACE跨平臺(tái)底層類(lèi)開(kāi)發(fā),為所有平臺(tái)提供了通用統(tǒng)一的主動(dòng)式異步接口。
? Boost.Asio庫(kù),也是采取了類(lèi)似的這種方案來(lái)實(shí)現(xiàn)統(tǒng)一的IO異步接口。
<-----------
最近在項(xiàng)目中使用了Boost.Asio類(lèi)庫(kù),其就是以Proactor這種設(shè)計(jì)模式來(lái)實(shí)現(xiàn),參見(jiàn):Proactor(The Boost.Asio library is based on the Proactor pattern. This design note outlines the advantages and disadvantages of this approach.),其設(shè)計(jì)文檔鏈接:http://asio.sourceforge.net/boost_asio_0_3_7/libs/asio/doc/design/index.html
First, let us examine how the Proactor design pattern is implemented in asio, without reference to platform-specific details.
Proactor design pattern (adapted from [1])
當(dāng)然這兩I/O設(shè)計(jì)模式,也在ACE中被大量應(yīng)用,這在ACE的相關(guān)書(shū)籍中都有介紹,其中在“ACE開(kāi)發(fā)者”網(wǎng)站中有很多不錯(cuò)的介紹文章。
如:ACE技術(shù)論文集-第8章 前攝器(Proactor):用于為異步事件多路分離和分派處理器的對(duì)象行為模式
ACE技術(shù)論文集-第7章 ACE反應(yīng)堆(Reactor)的設(shè)計(jì)和使用:用于事件多路分離的面向?qū)ο髽?gòu)架
ACE程序員教程-第6章 反應(yīng)堆(Reactor):用于事件多路分離和分派的體系結(jié)構(gòu)模式
ACE應(yīng)用-第2章 JAWS:高性能Web服務(wù)器構(gòu)架
?
Proactor模式在單CPU單核系統(tǒng)應(yīng)用中有著無(wú)可比擬的優(yōu)勢(shì),現(xiàn)在面臨的問(wèn)題是:在多CPU多核的系統(tǒng)中,它如何更好地應(yīng)用多線(xiàn)程的優(yōu)勢(shì)呢???這是很值思考和實(shí)踐的,也許會(huì)產(chǎn)生另外一種設(shè)計(jì)模式來(lái)適應(yīng)發(fā)展的需要啦。
總結(jié)
以上是生活随笔為你收集整理的高性能I/O设计模式Reactor和Proactor的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ACE中的Proactor和Reacto
- 下一篇: ACE_Select_Reactor 一