一切像霧像雨又像風(fēng)
作者:CppExplore 網(wǎng)址:http://www.shnenglu.com/CppExplore/網(wǎng)絡(luò)請(qǐng)求包經(jīng)過網(wǎng)絡(luò)層(技術(shù)系列綜述(一))被解析翻譯成程序自定義的消息,之后被投遞到業(yè)務(wù)線程的線程消息隊(duì)列(技術(shù)系列綜述(二))中。業(yè)務(wù)線程在隊(duì)列的另一端取出消息,開始處理,這是本章要介紹的部分。業(yè)務(wù)處理部分:主要有會(huì)話類(Session)和會(huì)話管理類(SessionManager,常見該類為單例)。先給出類圖,后文詳細(xì)介紹:一 SessionManager的職責(zé):(1)繼承IMsgThread(技術(shù)系列綜述(二)),調(diào)用該類的start方法,啟動(dòng)業(yè)務(wù)線程(2)提供on_.../do_...方法(技術(shù)系列綜述(二)),供其它線程向業(yè)務(wù)線程投遞消息,以及消息在業(yè)務(wù)線程的處理入口。(3)主要的私有屬性是session類的容器對(duì)象。容器類的選型的依據(jù),首先是查詢性能,之后是插入刪除的性能。array:數(shù)組下標(biāo)為session對(duì)象的seesionid_(此處sessionid,不要理解為常見協(xié)議中的session字段,可以理解為session對(duì)象的索引)。可以做到插入刪除(參考內(nèi)存管理chunk分配算法)查詢都在o(1)完成,缺點(diǎn)不能動(dòng)態(tài)增大。同樣可以參考定長(zhǎng)內(nèi)存池的分配算法,動(dòng)態(tài)申請(qǐng)255個(gè)array為一個(gè)chunk,所有chunk使用vector管理,各chunk中array編號(hào)遞增255,同樣可以達(dá)到增刪查o(1)的效率。缺點(diǎn):(1)sessionid_重復(fù)使用,加上消息經(jīng)過消息隊(duì)列形成的處理延遲,可能造成下一個(gè)session對(duì)象處理上一個(gè)同樣sessionid的session對(duì)象遺留下來的消息,實(shí)際使用中每個(gè)session對(duì)象有自己的狀態(tài)機(jī),這種殘留的消息危害并不大。(2)需要自己實(shí)現(xiàn),對(duì)比map的o(logn),這點(diǎn)細(xì)微的性能提升無任何意義(也就是減少了幾次整型之間的對(duì)比)。相比不需要自己額外實(shí)現(xiàn)的普通數(shù)組還算有點(diǎn)實(shí)用價(jià)值。vector:如果被插入的session的sessionid是遞增的,查詢可以做到折半查找logn的性能,但隨機(jī)刪除造成的內(nèi)存移動(dòng)是o(n),無法接受。map:以紅黑樹為基礎(chǔ)實(shí)現(xiàn)。增刪查找的性能都可以平穩(wěn)的保持在o(logn),sessionid_為整型或者其operater<實(shí)現(xiàn)簡(jiǎn)單的時(shí)候是最常用的容器。hash_map:哈希表,使用大量?jī)?nèi)存盡量使數(shù)據(jù)均勻分布,查詢性能分hashcode的計(jì)算(hash函數(shù))和查找部分,hash函數(shù)一般為所有有效信息的移位計(jì)算(經(jīng)典的是字符串的33算法)疊加,查找部分最理想的是0(1),最差是0(n),取決于hash函數(shù)計(jì)算結(jié)果碰撞的幾率。當(dāng)sessionid_為字符串或者其operater<實(shí)現(xiàn)復(fù)雜的時(shí)候常用。(4)該類處理消息的方式舉例如下:(容器以map<int,session *> mapSessions_為例)
如上例所示,session管理類對(duì)消息的處理方式必須簡(jiǎn)單固定,方便可持續(xù)維護(hù)、擴(kuò)充。二 Session的職責(zé)(1)數(shù)據(jù)結(jié)構(gòu):每一路連接的業(yè)務(wù)處理部分,首先有sessionid_標(biāo)記session本身,其次包含業(yè)務(wù)處理需要的必須的數(shù)據(jù)部分,另外最重要的一個(gè)數(shù)據(jù)結(jié)構(gòu)就是狀態(tài)機(jī)了。(2)狀態(tài)機(jī)。狀態(tài)機(jī)標(biāo)識(shí)session對(duì)象的狀態(tài),接收外部輸入的事件,驅(qū)動(dòng)狀態(tài)機(jī)運(yùn)行,并作出行為響應(yīng)。詳細(xì)見《技術(shù)系列之 狀態(tài)機(jī)(一)》和《技術(shù)系列之 狀態(tài)機(jī)(二)》,不多說了。(3)方法。主要分兩類:on_msg和do_event。舉例如下:
注意:1、所有有可能改變session內(nèi)蘊(yùn)狀態(tài)的操作都必須納入狀態(tài)機(jī)的嚴(yán)格控制,不能存在不通過狀態(tài)機(jī)即可改變session內(nèi)蘊(yùn)狀態(tài)的操作入口。2、如果兩個(gè)狀態(tài)對(duì)同樣的事件做出同樣的反應(yīng),并且都遷移到相同的狀態(tài),那么這兩個(gè)是同一個(gè)狀態(tài)。3、盡可能減少狀態(tài)的個(gè)數(shù)。如果兩個(gè)狀態(tài)具有嚴(yán)格的時(shí)序關(guān)系,處理的事件不同并且有嚴(yán)格的時(shí)序關(guān)系,那么考慮合并這兩個(gè)狀態(tài),防止?fàn)顟B(tài)機(jī)膨脹。
三 總結(jié):理解業(yè)務(wù)部分,先區(qū)分消息(Msg)和事件(Event)。1、消息(Msg):是指線程之間傳遞的數(shù)據(jù)結(jié)構(gòu),即被投遞到線程消息隊(duì)列中的數(shù)據(jù)結(jié)構(gòu)。SessionManager主要職責(zé)是接收消息,通過消息映射,找到處理該消息的函數(shù),該函數(shù)根據(jù)消息中攜帶的sessionid,找到session對(duì)象,調(diào)用該session的消息處理函數(shù)繼續(xù)后續(xù)的處理。2、事件(Event):是指被session對(duì)象中的狀態(tài)機(jī)處理的數(shù)據(jù)結(jié)構(gòu)。該數(shù)據(jù)結(jié)構(gòu),在session的消息處理函數(shù)中通過消息的內(nèi)容拼湊,之后交給狀態(tài)機(jī)對(duì)象處理,狀態(tài)機(jī)對(duì)象根據(jù)事件類型,通過事件映射,找到處理該事件的函數(shù),繼續(xù)該事件的處理。3、代碼流程:一般情況下(邏輯控制部分)其它線程不能直接調(diào)用session對(duì)象,正確的調(diào)用方式是發(fā)消息SessionManager,SessionManager根據(jù)消息找到session對(duì)象再進(jìn)行后續(xù)處理。4、代碼要寫的足夠呆板。 寫出好的系統(tǒng)關(guān)鍵在于對(duì)業(yè)務(wù)的理解,不在于對(duì)代碼技巧的玩弄。
Powered by: C++博客 Copyright © cppexplore