兩種高性能IO設(shè)計(jì)模式的比較_第1頁(yè)
兩種高性能IO設(shè)計(jì)模式的比較_第2頁(yè)
兩種高性能IO設(shè)計(jì)模式的比較_第3頁(yè)
兩種高性能IO設(shè)計(jì)模式的比較_第4頁(yè)
兩種高性能IO設(shè)計(jì)模式的比較_第5頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、兩種高性能I/O設(shè)計(jì)模式(Reactor/Proactor)的比較這篇文章探討并比較兩種用于TCP服務(wù)器的高性能設(shè)計(jì)模式.除了介紹現(xiàn)有的解決方案, 還提出了一種更具伸縮性,只需要維護(hù)一份代碼并且跨平臺(tái)的解決方案(含代碼示例),以及 其在不同平臺(tái)上的微調(diào).此文還比較了 java,c#,c+對(duì)各自現(xiàn)有以及提到的解決方案的實(shí) 現(xiàn)性能.系統(tǒng)I/O可分為阻塞型,非阻塞同步型以及非阻塞異步型1,2.阻塞型I/O意味著控制 權(quán)只到調(diào)用操作結(jié)束了才會(huì)回到調(diào)用者手里.結(jié)果調(diào)用者被阻塞了,這段時(shí)間了做不了任 何其它事情.更郁悶的是,在等待IO結(jié)果的時(shí)間里,調(diào)用者所在線程此時(shí)無(wú)法騰出手來去響 應(yīng)其它的請(qǐng)求,這真是太

2、浪費(fèi)資源了。拿read()操作來說吧,調(diào)用此函數(shù)的代碼會(huì)一直僵 在此處直至它所讀的socket緩存中有數(shù)據(jù)到來.相比之下,非阻塞同步是會(huì)立即返回控制權(quán)給調(diào)用者的。調(diào)用者不需要等等,它從調(diào)用的函 數(shù)獲取兩種結(jié)果:要么此次調(diào)用成功進(jìn)行了;要么系統(tǒng)返回錯(cuò)誤標(biāo)識(shí)告訴調(diào)用者當(dāng)前資源不 可用,你再等等或者再試度看吧。比如read()操作,如果當(dāng)前socket無(wú)數(shù)據(jù)可讀,則立即 返回EWOULBLOCK/EAGAIN,告訴調(diào)用read()者”數(shù)據(jù)還沒準(zhǔn)備好,你稍后再試”. 在非阻塞異步調(diào)用中,稍有不同。調(diào)用函數(shù)在立即返回時(shí),還告訴調(diào)用者,這次請(qǐng)求已經(jīng)開 始了。系統(tǒng)會(huì)使用另外的資源或者線程來完成這次調(diào)用操作,

3、并在完成的時(shí)候知會(huì)調(diào)用者(比 如通過回調(diào)函數(shù))。拿Windows的ReadFile()或者POSIX的aio_read()來說,調(diào)用 它之后,函數(shù)立即返回,操作系統(tǒng)在后臺(tái)同時(shí)開始讀操作。在以上三種IO形式中,非阻塞異步是性能最高、伸縮性最好的。這篇文章探討不同的I/O利用機(jī)制并提供一種跨平臺(tái)的設(shè)計(jì)模式(解決方案).希望此文可 以給于TCP高性能服務(wù)器開發(fā)者一些幫助,選擇最佳的設(shè)計(jì)方案。下面我們會(huì)比較Java, c#, C+各自對(duì)探討方案的實(shí)現(xiàn)以及性能.我們?cè)谖恼碌暮竺婢筒辉偬峒白枞降姆桨噶耍?因?yàn)樽枞絀/O實(shí)在是缺少可伸縮性,性能也達(dá)不到高性能服務(wù)器的要求。兩種IO多路復(fù)用方案:React

4、or and Proactor一般情況下,I/O復(fù)用機(jī)制需要事件分享器(event demultiplexor 1, 3).事件分享器 的作用,即將那些讀寫事件源分發(fā)給各讀寫事件的處理者,就像送快遞的在樓下喊:誰(shuí)的什 么東西送了,快來拿吧。開發(fā)人員在開始的時(shí)候需要在分享器那里注冊(cè)感興趣的事件,并提 供相應(yīng)的處理者(event handlers),或者是回調(diào)函數(shù);事件分享器在適當(dāng)?shù)臅r(shí)候會(huì)將請(qǐng)求 的事件分發(fā)給這些handler或者回調(diào)函數(shù).涉及到事件分享器的兩種模式稱為:Reactor and Proactor 1. Reactor模式是基于同 步I/O的,而Proactor模式是和異步I/O相關(guān)

5、的.在Reactor模式中,事件分離者等待 某個(gè)事件或者可應(yīng)用或個(gè)操作的狀態(tài)發(fā)生(比如文件描述符可讀寫,或者是socket可讀寫), 事件分離者就把這個(gè)事件傳給事先注冊(cè)的事件處理函數(shù)或者回調(diào)函數(shù),由后者來做實(shí)際的讀 寫操作。而在Proactor模式中,事件處理者(或者代由事件分離者發(fā)起)直接發(fā)起一個(gè)異步讀寫操作 (相當(dāng)于請(qǐng)求),而實(shí)際的工作是由操作系統(tǒng)來完成的。發(fā)起時(shí),需要提供的參數(shù)包括用于存 放讀到數(shù)據(jù)的緩存區(qū),讀的數(shù)據(jù)大小,或者用于存放外發(fā)數(shù)據(jù)的緩存區(qū),以及這個(gè)請(qǐng)求完后 的回調(diào)函數(shù)等信息。事件分離者得知了這個(gè)請(qǐng)求,它默默等待這個(gè)請(qǐng)求的完成,然后轉(zhuǎn)發(fā)完 成事件給相應(yīng)的事件處理者或者回調(diào)。舉例

6、來說,在Windows上事件處理者投遞了一個(gè)異 步IO操作(稱有overlapped的技術(shù)),事件分離者等IOCompletion事件完成1.這種 異步模式的典型實(shí)現(xiàn)是基于操作系統(tǒng)底層異步API的,所以我們可稱之為系統(tǒng)級(jí)別的或 者真正意義上的異步,因?yàn)榫唧w的讀寫是由操作系統(tǒng)代勞的。舉另外個(gè)例子來更好地理解Reactor與Proactor兩種模式的區(qū)別。這里我們只關(guān)注read 操作,因?yàn)閣rite操作也是差不多的。下面是Reactor的做法: 某個(gè)事件處理者宣稱它對(duì)某個(gè)socket上的讀事件很感興趣;事件分離者等著這個(gè)事件的發(fā)生;當(dāng)事件發(fā)生了,事件分離器被喚醒,這負(fù)責(zé)通知先前那個(gè)事件處理者;事件

7、處理者收到消息,于是去那個(gè)socket上讀數(shù)據(jù)了.如果需要,它再次宣稱對(duì)這個(gè) socket上的讀事件感興趣,一直重復(fù)上面的步驟;下面再來看看真正意義的異步模式Proactor是如何做的:事件處理者直接投遞發(fā)一個(gè)寫操作(當(dāng)然,操作系統(tǒng)必須支持這個(gè)異步操作).這個(gè)時(shí)候, 事件處理者根本不關(guān)心讀事件,它只管發(fā)這么個(gè)請(qǐng)求,它魂?duì)繅?mèng)縈的是這個(gè)寫操作的 完成事件。這個(gè)處理者很拽,發(fā)個(gè)命令就不管具體的事情了,只等著別人(系統(tǒng))幫 他搞定的時(shí)候給他回個(gè)話。事件分離者等著這個(gè)讀事件的完成(比較下與Reactor的不同);當(dāng)事件分離者默默等待完成事情到來的同時(shí),操作系統(tǒng)已經(jīng)在一邊開始干活了,它從 目標(biāo)讀取數(shù)據(jù),放

8、入用戶提供的緩存區(qū)中,最后通知事件分離者,這個(gè)事情我搞完了;事件分享者通知之前的事件處理者:你吩咐的事情搞定了;事件處理者這時(shí)會(huì)發(fā)現(xiàn)想要讀的數(shù)據(jù)已經(jīng)乖乖地放在他提供的緩存區(qū)中,想怎么處理 都行了。如果有需要,事件處理者還像之前一樣發(fā)起另外一個(gè)寫操作,和上面的幾個(gè) 步驟一樣?,F(xiàn)行做法開源C+開發(fā)框架ACE1, 3(Douglas Schmidt, et al.開發(fā))提供了大量平臺(tái)獨(dú)立的 底層并發(fā)支持類(線程、互斥量等).同時(shí)在更高一層它也提供了獨(dú)立的幾組C+類,用于 實(shí)現(xiàn)Reactor及Proactor模式。盡管它們都是平臺(tái)獨(dú)立的單元,但他們都提供了不同的接 口.ACE Proactor在MS-

9、Windows上無(wú)論是性能還在健壯性都更勝一籌,這主要是由于 Windows提供了一系列高效的底層異步API. 4, 5.(這段可能過時(shí)了點(diǎn)吧)不幸的是,并不是所有操作系統(tǒng)都為底層異步提供健壯的支持。舉例 來說,許多Unix系統(tǒng)就有麻煩.因此,ACE Reactor可能是Unix系統(tǒng)上更合適的解決方案. 正因?yàn)橄到y(tǒng)底層的支持力度不一,為了在各系統(tǒng)上有更好的性能,開發(fā)者不得不維護(hù)獨(dú)立的 好幾份代碼:為Windows準(zhǔn)備的ACE Proactor以及為Unix系列提供的ACE Reactor.就像我們提到過的,真正的異步模式需要操作系統(tǒng)級(jí)別的支持。由于事件處理者及操作系統(tǒng) 交互的差異,為React

10、or和Proactor設(shè)計(jì)一種通用統(tǒng)一的外部接口是非常困難的。這也是 設(shè)計(jì)通行開發(fā)框架的難點(diǎn)所在。更好的解決方案在文章這一段時(shí),我們將嘗試提供一種融合了 Proactor和Reactor兩種模式的解決方案. 為了演示這個(gè)方案,我們將Reactor稍做調(diào)整,模擬成異步的Proactor模型(主要是在事 件分離器里完成本該事件處理者做的實(shí)際讀寫工作,我們稱這種方法為”模擬異步”)。下面的 示例可以看看read操作是如何完成的:事件處理者宣稱對(duì)讀事件感興趣,并提供了用于存儲(chǔ)結(jié)果的緩存區(qū)、讀數(shù)據(jù)長(zhǎng)度等參數(shù);調(diào)試者等待(比如通過select。);當(dāng)有事件到來(即可讀),調(diào)試者被喚醒,調(diào)試者去執(zhí)行非阻塞的

11、讀操作(前面事件處理 者已經(jīng)給了足夠的信息了)。讀完后,它去通知事件處理者。事件處理者這時(shí)被知會(huì)讀操作已完成,它擁有完整的原先想要獲取的數(shù)據(jù)了.我們看到,通過為分離者(也就上面的調(diào)試者)添加一些功能,可以讓Reactor模式轉(zhuǎn)換為 Proactor模式。所有這些被執(zhí)行的操作,其實(shí)是和Reactor模型應(yīng)用時(shí)完全一致的。我們 只是把工作打散分配給不同的角色去完成而已。這樣并不會(huì)有額外的開銷,也不會(huì)有性能上 的的損失,我們可以再仔細(xì)看看下面的兩個(gè)過程,他們實(shí)際上完成了一樣的事情:標(biāo)準(zhǔn)的經(jīng)典的Reactor模式:步驟1)等待事件(Reactor的工作)步驟2)發(fā)已經(jīng)可讀”事件發(fā)給事先注冊(cè)的事件處理者

12、或者回調(diào)(Reactor要做的) 步驟3)讀數(shù)據(jù)(用戶代碼要做的)步驟4)處理數(shù)據(jù)(用戶代碼要做的)模擬的Proactor模式:步驟1)等待事件(Proactor的工作)步驟2)讀數(shù)據(jù)(看,這里變成成了讓Proactor做這個(gè)事情)步驟3)把數(shù)據(jù)已經(jīng)準(zhǔn)備好的消息給用戶處理函數(shù),即事件處理者(Proactor要做的) 步驟4)處理數(shù)據(jù)(用戶代碼要做的)在沒有底層異步I/O API支持的操作系統(tǒng),這種方法可以幫我們隱藏掉socket接口的差異 (無(wú)論是性能還是其它),提供一個(gè)完全可用的統(tǒng)一異步接口。這樣我們就可以開發(fā)真正平 臺(tái)獨(dú)立的通用接口了。TProactor我們提出的TProactor方案已經(jīng)

13、由TerabitP/L 6公司實(shí)現(xiàn)了.它有兩種實(shí)現(xiàn):C+的和 Java的.C+版本使用了 ACE平臺(tái)獨(dú)立的底層元件,最終在所有操作系統(tǒng)上提供了統(tǒng)一的 異步接口。TProactor中最重要的組件要數(shù)Engine和WaitStrategy 了. Engine用于維護(hù)異步操作 的生命周期;而WaitStrategy用于管理并發(fā)策略.WaitStrategy和Engine 一般是成對(duì) 出現(xiàn)的,兩者間提供了良好的匹配接口.Engines和等待策略被設(shè)計(jì)成高度可組合的(完整的實(shí)現(xiàn)列表請(qǐng)參照附錄1)。TProactor 是高度可配置的方案,通過使用異步內(nèi)核API和同步Unix API(select(),po

14、ll(), /dev/poll (Solaris 5.8+), port_get (Solaris 5.10),RealTime (RT) signals (Linux 2.4+), epoll (Linux 2.6), k-queue (FreeBSD),)它內(nèi)部實(shí)現(xiàn)了三種引擎(POSIX AIO, SUN AIO and Emulated 【。并隱藏了六類等待策略。TProactor實(shí)現(xiàn)了和標(biāo)準(zhǔn)的ACE Proactor 一樣的接口。這樣一來,為不同平臺(tái)提供通用統(tǒng)一的只有一份代碼的跨平臺(tái)解決 方案成為可能。Engines和WaitStrategies可以像樂高積木一樣自由地組合,開發(fā)者可以

15、在運(yùn)行時(shí)通過配 置參數(shù)來選擇合適的內(nèi)部機(jī)制(引擎和等待策略)??梢愿鶕?jù)需求設(shè)定配置,比如連接數(shù), 系統(tǒng)伸縮性,以及運(yùn)行的操作系統(tǒng)等。如果系統(tǒng)支持相應(yīng)的異步底層API,開發(fā)人員可以選 擇真正的異步策略,否則用戶也可以選擇使用模擬出來的異步模式。所有這一切策略上的實(shí) 現(xiàn)細(xì)節(jié)都不太需要關(guān)注,我們看到的是一個(gè)可用的異步模型。舉例來說,對(duì)于運(yùn)行在Sun Solaris上的HTTP服務(wù)器,如果需要支持大量的連接數(shù), /dev/poll或者port_get()之類的引擎是比較合適的選擇;如果需要高吞吐量,那使用基 本select()的引擎會(huì)更好。由于不同選擇策略內(nèi)在算法的問題,像這樣的彈性選擇是標(biāo)準(zhǔn) ACE

16、 Reactor/Proactor模式所無(wú)法提供的(見附錄2)。在性能方面,我們的測(cè)試顯示,模擬異步模式并未造成任何開銷,沒有變慢,反倒是性能有 所提升。根據(jù)我們的測(cè)試結(jié)果,TProactor相較標(biāo)簽的ACE Reactor在Unix/Linux系統(tǒng) 上有大約10-35%性能提升,而在Windows上差不多(測(cè)試了吞吐量及響應(yīng)時(shí)間)。性能比較(JAVA / C+ / C#).除了 C+,我們也在Java中實(shí)現(xiàn)了 TProactor. JDK1.4中,Java僅提供了同步方法,像 C中的select。7, 8. Java TProactor基于Java的非阻塞功能(java.nio包),類似于

17、C+ + 的 TProactor 使用了 select()引擎.圖1、2顯示了以bits/sec為單位的傳輸速度以及相應(yīng)的連接數(shù)。這些圖比較了以下三種 方式實(shí)現(xiàn)的echo服務(wù)器:標(biāo)準(zhǔn)ACE Reactor實(shí)現(xiàn)(基于RedHat Linux9.0)、TProactor C+/Java實(shí)現(xiàn)(Microsoft Windows平臺(tái)及RedHat v9.0),以及C#實(shí)現(xiàn)。測(cè)試的時(shí)候, 三種服務(wù)器使用相同的客戶端瘋狂地連接,不間斷地發(fā)送固定大小的數(shù)據(jù)包。這幾組測(cè)試是在相同的硬件上做的,在不同硬件上做的相對(duì)結(jié)果對(duì)比也是類似。圖 1. Windows XP/P4 2.6GHz HyperThreading

18、/512 MB RAM.圖 2. Linux RedHat 2.4.20-smp/P4 2.6GHz HyperThreading/512 MB RAM.用戶代碼示例 下面是TProactor Java實(shí)現(xiàn)的echo服務(wù)器代碼框架。總的來說,開發(fā)者只需要實(shí)現(xiàn)兩個(gè) 接口:一是OpRead,提供存放讀結(jié)果的緩存;二是OpWrite,提供存儲(chǔ)待寫數(shù)據(jù)的緩存 區(qū)。同時(shí),開發(fā)者需要通過回調(diào)onReadComplated()和onWriteCompleted()實(shí)現(xiàn)協(xié)議 相關(guān)的業(yè)務(wù)代碼。這些回調(diào)會(huì)在合適的時(shí)候被調(diào)用.classEchoServerProtocol implements AsynchHand

19、ler AsynchChannelachannel = null;EchoServerProtocol(Demultiplexor m, SelectableChannel channel ) throws ExceptionAsynchChannel( m, this, channel );this.achannel = newthrows Exceptionpublic void start()construction/ called afterSystem.out.println(Thread.currentThread().getName() +:EchoServer protocol

20、 started);achannel.read( buffer);public void onReadCompleted( OpReadopRead ) throws Exceptionif ( opRead.getError() != null )/ handle error, do clean-up if neededSystem.out.println( EchoServer:readCompleted: +opRead.getError().toString();achannel.close();return;if ( opRead.getBytesCompleted () = 0)S

21、ystem.out.println(EchoServer:readCompleted: Peer closed ”+ opRead.getBytesCompleted();achannel.close();return;ByteBuffer buffer = opRead.getBuffer();achannel.write(buffer);public void onWriteCompleted(OpWriteopWrite)throws Exception/ logically similar to onReadCompleted 結(jié)束語(yǔ)TProactor為多個(gè)平臺(tái)提供了一個(gè)通用、彈性、可

22、配置的高性能通訊組件,所有那些在附錄 2中提到的問題都被很好地隱藏在內(nèi)部實(shí)現(xiàn)中了。從上面的圖中我們可以看出C+仍舊是編寫高性能服務(wù)器最佳選擇,雖然Java已緊隨其 后。然而因?yàn)镴ava本身實(shí)現(xiàn)上的問題,其在Windows上表現(xiàn)不佳(這已經(jīng)應(yīng)該成為歷史 了吧)。需要注意的是,以上針對(duì)Java的測(cè)試,都是以裸數(shù)據(jù)的形式測(cè)試的,未涉及到數(shù)據(jù)的處理 (影響性能)??v觀AIO在Linux上的快速發(fā)展9,我們可以預(yù)計(jì)Linux內(nèi)核API將會(huì)提供大量更加強(qiáng) 健的異步API,如此一來以后基于此而實(shí)現(xiàn)的新的Engine/等待策略將能輕松地解決能用 性方面的問題,并且這也能讓標(biāo)準(zhǔn)ACE Proactor接口受益。

23、附錄ITProactor中實(shí)現(xiàn)的Engines和等待策略引擎類型等待策操作引擎類型略系統(tǒng)POSIX_AIO (true async) aio_read() /aio_write ()aio_su spend( )Waitin g for RT signal Callba ck functi onPOSI X comp laine d UNIX (not robu st) POSI X (not robu st) SGI IRIX, LINU X (not robu st)SUN_AIO (true async) aio_read() /aio_write ()aio_ wait ()SU N

24、(no t rob ust )EmulatedAsyncNon-blockingread() /write()sel ect () pol l()/de v/p oll Linu x RT sign alsKqu euegenericPOSIXMostly all POSIX implem entatio ns SUN Linux FreeBSD附錄II所有同步等待策略可劃分為兩組:edge-triggered (e.g. Linux 實(shí)時(shí)信號(hào))-signal readiness only when socket became ready (changes state);level-trigg

25、ered (e.g. select(), poll(), /dev/poll) - readiness at any time.讓我們看看這兩組的一些普遍的邏輯問題:edge-triggered group: after executing I/O operation, the demultiplexing loop can lose the state of socket readiness. Example: the read handler did not read whole chunk of data, so the socket remains still ready for re

26、ad. But the demultiplexor loop will not receive next notification.level-triggered group: when demultiplexor loop detects readiness, it starts the write/read user defined handler. But before the start, it should remove socket descriptior from theset of monitored descriptors. Otherwise, the same event

27、 can be dispatched twice.Obviously, solving these problems adds extra complexities to development. All these problems were resolved internally within TProactor and the developer should not worry about those details, while in the synch approach one needs to apply extra effort to resolve them.資源Dougla

28、s C. Schmidt, Stephen D. Huston C+ Network Programming. 2002, Addison-Wesley ISBN 0-201-60464-7W. Richard Stevens UNIX Network Programming vol. 1 and 2, 1999, Prentice Hill, ISBN 0-13- 490012-XDouglas C. Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann Pattern-Oriented Software Architecture: Pat

29、terns for Concurrent and Networked Objects, Volume 2 Wiley & Sons, NY 2000INFO: Socket Overlapped I/O Versus Blocking/Non-blocking Mode.Q181611. Microsoft Knowledge Base Articles.Microsoft MSDN. I/O Completion Ports./library/default.asp?url=/library/en- us/fileio/fs/i_o_completion_ports.aspTProactor (ACE compatible Proactor). HYPERLINK .au .auJavaDocjava.nio.channels HYPERLINK /j2se/142/docs/api/java/nio/channels/package-summar /j2se/142/docs/api/java/nio/channels/package-summar y.htmlJavaDocJava.nio.channels.spi Class SelectorProvider HYPERLINK http

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論