西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴(lài)的軟件下載站!
軟件
軟件
文章
搜索

首頁(yè)編程開(kāi)發(fā)其它知識(shí) → 多線程游戲服務(wù)器技術(shù)開(kāi)發(fā)

多線程游戲服務(wù)器技術(shù)開(kāi)發(fā)

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:本站整理時(shí)間:2010/12/13 8:53:15字體大。A-A+

作者:佚名點(diǎn)擊:152次評(píng)論:0次標(biāo)簽: 地圖 線程 游戲服務(wù)器

  • 類(lèi)型:修改器(游戲工具)大。16.2M語(yǔ)言:中文 評(píng)分:2.5
  • 標(biāo)簽:
立即下載
 這些東西是平時(shí)遇到的, 覺(jué)得有一定的價(jià)值, 所以記錄下來(lái), 以后遇到類(lèi)似的問(wèn)題可以查閱, 同時(shí)分享出來(lái)也能方便需要的人

寫(xiě)在前面的
存在即合理, 不管什么事, 都是有原因有理由有前提的, 所以在談?wù)撝拔覀兿纫鞔_一些東西
1. 服務(wù)器端使用多線程的必要條件是多核, 且物理核的計(jì)算能力總和>>服務(wù)器程序的計(jì)算量. 如果不滿足上述條件, 應(yīng)該先考慮硬件配置問(wèn)題.
2. 為什么要用多線程? 是為了充分利用多核增加計(jì)算量, 增大計(jì)算量的目的是什么? 支持更為復(fù)雜的玩法. 這里有很重要的信息, 那就是"支持更為復(fù)雜的玩法"是目的, 而"增加計(jì)算量"是達(dá)到目的的手段; 前者是策劃域問(wèn)題, 而后者是程序域問(wèn)題. 一個(gè)需求和實(shí)現(xiàn)的結(jié)合點(diǎn).
3. 當(dāng)計(jì)算量達(dá)到時(shí), 其他短板開(kāi)始起作用, 也就是說(shuō)不要去追求所謂最好利用計(jì)算量之方法, 轉(zhuǎn)而追求計(jì)算量不要成為最短板即可.
這片文章是在有"支持更為復(fù)雜的玩法"這樣的需求, 且當(dāng)前存在"計(jì)算量目前是最短板", 且"由于沒(méi)有充分利用多線程發(fā)揮機(jī)器多核計(jì)算量即計(jì)算量有較多剩余"的情況下的一些探討和心得.
申明: 本文并不想得出任何"我這個(gè)就對(duì)!"的方案, 只是將我在實(shí)踐中遇到的問(wèn)題, 和解決問(wèn)題或是看到的一些思路寫(xiě)出來(lái), 期望能引發(fā)大家的探討:) 相比之下文中提高的方案只不過(guò)是一個(gè)example罷了

一個(gè)地圖一個(gè)線程的方案
關(guān)于在游戲服務(wù)器中使用多線程, 有一個(gè)常常被提到的方案是: 一個(gè)地圖一個(gè)線程, 這個(gè)方案的一個(gè)推廣就是平行子系統(tǒng)中每個(gè)子系統(tǒng)對(duì)應(yīng)一個(gè)線程. 個(gè)人認(rèn)為這個(gè)方案還是值得商榷的. 下面來(lái)說(shuō)明一下我的看法.
根據(jù)一些講解系統(tǒng)的名著中的定義: 在問(wèn)題域的世界中, 交互聯(lián)系格外緊密的一群實(shí)體之間形成了一個(gè)系統(tǒng). 一個(gè)子系統(tǒng)之所以被劃分成為一個(gè)子系統(tǒng), 是因?yàn)樵谧酉到y(tǒng)中的成員的交互和聯(lián)系頻率要遠(yuǎn)遠(yuǎn)大于和系統(tǒng)外實(shí)體的交互和聯(lián)系, 這是一個(gè)很重要的結(jié)論. 我們可以從這里得到一個(gè)推論: 劃分良好的子系統(tǒng)內(nèi)部交互非常緊密, 和外部實(shí)體交互相對(duì)較弱. 很巧的是我們?cè)谠O(shè)計(jì)中往往會(huì)把這里的子系統(tǒng)劃分為程序中的一個(gè)功能模塊, 模塊也有這樣的性質(zhì), 模塊中的交互要遠(yuǎn)遠(yuǎn)大于模塊間的交互.
有了上述理論的支持, 再來(lái)看看為什么說(shuō)"一個(gè)地圖一個(gè)線程"這樣的方案不可取? 一個(gè)地圖是一個(gè)子系統(tǒng), 地圖間的交互是非常小的, 的確是這樣, 可能就是在不同地圖中移動(dòng)時(shí)等不頻繁事件. 這里可以分析一下"地圖綁定線程"這個(gè)想法的依據(jù):
1. 增大計(jì)算量. 在系統(tǒng)中引入多線程, 利用多核, 加大服務(wù)器端的計(jì)算能力(提供更多的游戲邏輯處理), 這樣就可以在一個(gè)服務(wù)器上容納更多的玩家.
2. 防止犯錯(cuò). 避開(kāi)多線程的鎖的問(wèn)題, 把交互性強(qiáng)的部分分在同一個(gè)線程中, 這樣的話在大部分情況下避免鎖, 只有在很少的跨地圖交互時(shí)才使用同步方法來(lái)保證[避免鎖可以防止鎖的競(jìng)爭(zhēng), 更重要的是在實(shí)際編程中解放程序員, 因?yàn)闀r(shí)刻考慮多線程問(wèn)題太痛苦了, 犯錯(cuò)不可避免]. 放在這里就可以發(fā)現(xiàn)按地圖劃分是一個(gè)很好的劃分線程的方法.
該方法的問(wèn)題在于首先它不一定很發(fā)揮出多核的效果, 因?yàn)橛螒蛑腥瞬惶珪?huì)是均勻的分布在多個(gè)地圖上. 這樣就會(huì)產(chǎn)生有的線程都忙不過(guò)來(lái)了[地圖人很多], 有的線程很閑[地圖人很少], 問(wèn)題的本質(zhì)是這種使用線程的方法限制了每個(gè)地圖的可使用計(jì)算量[無(wú)形中的一個(gè)假設(shè)是: 單個(gè)核的計(jì)算量是足夠的, 一旦現(xiàn)實(shí)情況不符, 服務(wù)器端就會(huì)掉幀], 也就是說(shuō)對(duì)每個(gè)地圖來(lái)說(shuō), 還是單線程的, 并沒(méi)有達(dá)到想要的"增大計(jì)算量"的目地. 其次, 系統(tǒng)的穩(wěn)定性差, 因?yàn)橹灰幸粋(gè)線程core掉, 后果可想而知. 再次, 暫時(shí)不談前兩個(gè)問(wèn)題, 那么在計(jì)算量得到充分滿足的條件下, 根據(jù)"短板效應(yīng)", 你的系統(tǒng)的能力又會(huì)開(kāi)始受到內(nèi)存, 網(wǎng)絡(luò)等其他因素的影響, 這時(shí)你可能會(huì)想要在其他機(jī)器上橫向擴(kuò)展系統(tǒng), 你必須單獨(dú)設(shè)計(jì)這一部分, 多線程體系本來(lái)就有"我能發(fā)揮機(jī)器的計(jì)算能力, 計(jì)算量從此不是問(wèn)題"這樣的傾向, 但是它的一個(gè)不可回避的問(wèn)題就是, 多線程的執(zhí)行流共享程序進(jìn)程空間, 它必須在同一臺(tái)主機(jī)上. 分布式的橫向擴(kuò)展對(duì)多線程來(lái)說(shuō)是另一個(gè)課題, 它從來(lái)沒(méi)想過(guò)這個(gè), 你得自己去實(shí)現(xiàn).
其實(shí)根據(jù)設(shè)計(jì)的特點(diǎn), 這里還不如只用多進(jìn)程來(lái)代替多線程, 因?yàn)?
1. 多進(jìn)程同樣發(fā)揮多核的計(jì)算能力, 至少在"地圖綁定線程"這個(gè)問(wèn)題上不弱于多線程, 但也不會(huì)強(qiáng), 因?yàn)橐彩艿絾尉程地圖的影響.
2. 多進(jìn)程穩(wěn)定性好, 一個(gè)地圖進(jìn)程core了, 其他地圖不受影響.
3. 使用socket進(jìn)行地圖[進(jìn)程]間通信手段, 天然支持分布式部署, 在系統(tǒng)需要橫向擴(kuò)展時(shí), 不用做任何的額外工作.
總的來(lái)說(shuō), 這種平行子系統(tǒng)中一個(gè)子系統(tǒng)對(duì)應(yīng)一個(gè)線程的方法看似使用的多線程, 但是本質(zhì)上還是單線程的設(shè)計(jì)思路, 所以不是一種很好的方案, 但是這個(gè)方法有它的可行性和合理性, 因?yàn)樗拇_是分?jǐn)偭擞?jì)算量, 而且不用過(guò)度考慮鎖的問(wèn)題, 所以它還是有很重要的參考價(jià)值.

去現(xiàn)實(shí)世界中尋找答案
另一個(gè)想法是, 游戲世界中的每一個(gè)active obj都有一個(gè)線程+一個(gè)消息對(duì)列. 這個(gè)想法看起來(lái)不現(xiàn)實(shí), 但是它是出于對(duì)現(xiàn)實(shí)世界中可響應(yīng)的實(shí)體的最好模擬. 我記得剛工作的時(shí)候, 帶我的人最后也是my friend的--徐曉剛同學(xué)就告訴我, 游戲中的實(shí)體一定要和現(xiàn)實(shí)生活中的類(lèi)似實(shí)體有對(duì)應(yīng), 現(xiàn)實(shí)實(shí)體是怎么樣的, 你游戲中的實(shí)體就做成什么樣, 當(dāng)時(shí)我聽(tīng)了覺(jué)得不對(duì)啊, 不是要抽象么什么什么的, 典型的書(shū)看多了, 但是現(xiàn)在看來(lái)確實(shí)是這樣的, 游戲中的實(shí)體都是源于生活的, 要想做一個(gè)好的模擬, 還是得觀察和研究現(xiàn)實(shí)中的實(shí)體才行.
比如現(xiàn)實(shí)生活中確實(shí)就是這樣, 可以有反應(yīng)的實(shí)體都是時(shí)刻在接受著外界的信息(消息), 然后它的反應(yīng)其實(shí)就是在處理這個(gè)信息[在它自己的線程里處理這個(gè)消息]. 比如說(shuō), 你丟一個(gè)骨頭給一個(gè)小狗, 就相當(dāng)于給它發(fā)了個(gè)消息[你有吃的了], 小狗就會(huì)處理這個(gè)消息[啃骨頭]. 再比如說(shuō), 媽媽告訴小孩, 去把垃圾倒了, 小孩聽(tīng)到這個(gè)消息, 就會(huì)去倒垃圾. 可以看出來(lái), 這都是 可執(zhí)行體+消息 的結(jié)構(gòu). 當(dāng)然, 媽媽也可以告訴小孩, 你去把垃圾倒了, 然后再去商店買(mǎi)一點(diǎn)鹽. 小孩收到這兩個(gè)消息的時(shí)候, 就會(huì)記下來(lái), 先去到垃圾, 然后去買(mǎi)鹽, 這個(gè)其實(shí)相當(dāng)于小孩有一個(gè)記錄消息的隊(duì)列, 他會(huì)依次處理隊(duì)列中的消息.
所以這里我個(gè)人得出的結(jié)論是在多線程系統(tǒng)中:
1. 系統(tǒng)本身是內(nèi)聚封閉的, 它不能直接去查看不是自己內(nèi)部的數(shù)據(jù), 方法等, 別人也不能直接來(lái)查看它的相關(guān)信息, 系統(tǒng)只負(fù)責(zé)維護(hù)自己的狀態(tài).
2. 如果需要交互, 系統(tǒng)間應(yīng)該顯式的走消息機(jī)制.
在現(xiàn)實(shí)生活中找到有反應(yīng)的實(shí)體并觀察它們的行為后, 就可以尋找它們的共同點(diǎn), 這個(gè)過(guò)程就是抽象, 抽象并不是打開(kāi)編輯器, 想著自己要寫(xiě)代碼來(lái)抽象這個(gè)問(wèn)題呀, 而是在現(xiàn)實(shí)中找到對(duì)應(yīng)并歸納共性的過(guò)程. 這里看到, 可以獨(dú)立的反應(yīng)的實(shí)體具有兩個(gè)性質(zhì):
1. 可以獨(dú)立行為---也就是說(shuō)他們是active的. 一個(gè)npc是一個(gè)系統(tǒng), 一個(gè)player也是一個(gè)系統(tǒng).
2. 有一個(gè)消息隊(duì)列---他們可以處理隊(duì)列中的消息.
映射到程序中, 可以獨(dú)立行為就單獨(dú)給它分一根線程唄, 消息隊(duì)列不是問(wèn)題, 每個(gè)線程的唯一任務(wù)就是處理消息隊(duì)列中的消息. 但是如果能這么簡(jiǎn)單就不叫"源于生活高于生活了". 這樣的弊端一看就看出來(lái)了, 游戲中每個(gè)有反應(yīng)的實(shí)體一個(gè)線程不現(xiàn)實(shí), 就拿我知道的來(lái)說(shuō), 5000個(gè)npc和2000個(gè)玩家吧, 都是有反應(yīng)的實(shí)體, 一共啟動(dòng)5000+2000=7000根線程, 顯然不現(xiàn)實(shí), 開(kāi)銷(xiāo)上受不了.
但是這個(gè)抽象的確很不錯(cuò), 很符合現(xiàn)實(shí), 所以我不想放棄它. 那么還是要從現(xiàn)實(shí)世界中學(xué)習(xí)如何"降低開(kāi)銷(xiāo)", 類(lèi)比一下, 比如一個(gè)食堂的老板, 他雇傭了一個(gè)洗白菜工, 一個(gè)洗芹菜工, 一個(gè)切白菜工, 一個(gè)切芹菜工, 一個(gè)炒白菜工, 一個(gè)炒芹菜工, 這樣的配置不能說(shuō)錯(cuò), 沒(méi)問(wèn)題可以工作, 不過(guò)過(guò)了幾天老板就發(fā)現(xiàn)了, 開(kāi)銷(xiāo)太大了, 每個(gè)月掙的不如花的多, 而且還有人員有大把空閑時(shí)間. 于是他讓洗菜的不管白菜芹菜一起洗, 切菜和炒菜的人也一樣. 這樣就剩下3個(gè)人了, 過(guò)了幾天后老板又開(kāi)掉了洗菜的人, 讓切菜的人兼上洗菜的活, 這樣就只剩下兩個(gè)人的人力開(kāi)銷(xiāo).
類(lèi)比到計(jì)算機(jī)中, 我們創(chuàng)建的線程就是雇傭工人, 工人不是免費(fèi)的, 是有人力成本的, 線程也一樣, 它不是免費(fèi)的, 是有開(kāi)銷(xiāo)的. 所以你創(chuàng)建不了太多的線程, 就和你請(qǐng)不起太多的員工是一個(gè)道理. 在現(xiàn)實(shí)生活中通過(guò)讓一個(gè)員工干更多的活, 來(lái)達(dá)到降低成本的方法, 在這里也是適用的.
首先講一個(gè)不易區(qū)分的地方, 就是"能動(dòng)"和"動(dòng)"的區(qū)別. 英文active和actor, 一個(gè)是形容詞, 一個(gè)是動(dòng)詞. 這個(gè)很重要, 因?yàn)槲覀兊南到y(tǒng)中, active object很多, 但是actor是需要控制的, 不可能太多. actor其實(shí)直接對(duì)應(yīng)于一個(gè)線程, 而active object對(duì)應(yīng)于諸多的可反應(yīng)的實(shí)體. 比如npc, player等等.我們需要用actor來(lái)驅(qū)動(dòng)active object, 沒(méi)有被驅(qū)動(dòng)的active object是靜止的, 只有用actor才能賦予它活力. 所以我們可以寫(xiě)下如下的代碼.

可反應(yīng)的實(shí)體的定義
class activeobj {
msgqueue mq;
void Active() {
processMsg(mq.PopFront());
}
void RecvWork(msg) {
mq.push(msg);
}
}

創(chuàng)建多個(gè)實(shí)體
activeobj objs[34];

actor驅(qū)動(dòng)實(shí)體
void actor() {
while (true) {
foreach(obj in objs) {
obj.Active()
}
}
}
這里, 每個(gè)activeobj都有自己的消息隊(duì)列, 你可以使用RecvWork向activeobj發(fā)送消息, 而這個(gè)activeobj被actor激活的時(shí)候就會(huì)去處理自己消息隊(duì)列中的消息, 這樣整個(gè)世界中的obj都具有活力了, 下面代碼表示在多線程世界中上述代碼的形式, 也就是說(shuō), 存在多個(gè)actor

可反應(yīng)的實(shí)體的定義
class activeobj {
msgqueue mq;
lock mc;
void Active() {
mc.Lock();
msg m = mq.PopFront();
mc.Unlock();
processMsg(m);
}
void RecvWork(msg) {
mc.Lock();
mq.push(msg);
mc.Unlock();
}
}

創(chuàng)建多個(gè)實(shí)體
activeobj objs[100];

actor驅(qū)動(dòng)實(shí)體
void actor(int i) {
while (true) {
for (j = i * 25; j < (i + 1) * 25; ++j) {
objs[j].Active()
}
}
}

創(chuàng)建actor
createActor(actor, 0)
createActor(actor, 1)
createActor(actor, 2)
createActor(actor, 3)
上面演示的策略是創(chuàng)建4個(gè)actor, 每個(gè)actor負(fù)責(zé)驅(qū)動(dòng)固定的25個(gè)obj, 每個(gè)activeobj有自己的消息隊(duì)列鎖, 這樣就可以保證消息隊(duì)列的線程安全. 這樣的好處是比較簡(jiǎn)單, 但是這個(gè)做法的問(wèn)題也有很多:

1. 消息的時(shí)序不對(duì), 比如, 我先給obj[3]發(fā)了一個(gè)消息, 然后給obj[1]發(fā)了一個(gè)消息, 那么根據(jù)上面的邏輯, obj[1]的消息很可能會(huì)先于obj[3]被處理. 如果這兩個(gè)消息之間先后沒(méi)有關(guān)系還好, 但是一旦有邏輯上的先后關(guān)系, 這樣處理就是錯(cuò)誤的了. 問(wèn)題的根源是: 處理消息總是按照obj的排列順序, 而不是按照收到消息的前后順序.
2. 這種方法還是落入了不能平分負(fù)載的問(wèn)題中, 因?yàn)榭赡躠ctor1管理的obj群不活躍, 而actor2管理的obj群異常的活躍. 就會(huì)出現(xiàn)一個(gè)線程特別忙, 另一個(gè)線程閑置的狀態(tài), 在往下說(shuō), 就是有可能發(fā)生一個(gè)CPU 100%了, 另一個(gè)CPU20%, 但是游戲掉幀, 就是因?yàn)闆](méi)有均攤計(jì)算量. 這也可能成為一個(gè)優(yōu)點(diǎn), 因?yàn)椴粫?huì)出現(xiàn)兩個(gè)線程中同時(shí)處理一個(gè)obj的情況, 也就是說(shuō)對(duì)obj自身來(lái)說(shuō)是在單線程環(huán)境中的. 具有單線程的安全性.

改進(jìn)方案
所以我們必須繼續(xù)思考這個(gè)問(wèn)題, 上面的第二點(diǎn)好解決, 可以這樣

創(chuàng)建多個(gè)實(shí)體 …
lock oc;
activeobj GetObj() {
oc.Lock();
foreach(obj in objs) {
if (!obj.mq.empty()) {
objs.Remove(obj);
oc.Unlock();
return obj;
}
}
oc.Unlock();
return nullobj;
}

void actor() {
while (true) {
obj = GetObject();
if (obj != nullobj) {
obj.Active();
} else {
yield();
}
}
}
經(jīng)過(guò)上述改動(dòng)以后, 可以看到, 只要有一個(gè)線程空閑下來(lái), 它就會(huì)去查詢是否有obj存在msg等待被處理. 如果沒(méi)有, 線程就短暫的休息一下. 這樣的話, 計(jì)算量基本上可以實(shí)現(xiàn)均攤到多個(gè)線程上. 但是這種方案有明顯的一個(gè)鎖競(jìng)爭(zhēng)的hot point, 就是GetObj函數(shù)中. 這里不適合用重量級(jí)的鎖, 而且這里的競(jìng)爭(zhēng)會(huì)隨actor的數(shù)量上升而變得更激烈.
上面的方案算是一個(gè)解決計(jì)算分?jǐn)偟霓k法, 但是沒(méi)有解決消息的時(shí)序問(wèn)題. 話說(shuō)基于消息的系統(tǒng)成堆成堆的, 比如說(shuō)日常中用到的windows系統(tǒng)就是基于消息驅(qū)動(dòng)的, 可以從它身上學(xué)到一些東西. Windows的控件可以看做是active object, 因?yàn)樗梢詫?duì)你的操作進(jìn)行反應(yīng), 比如你點(diǎn)擊它, 拖動(dòng)它等等, 這些都是發(fā)消息來(lái)實(shí)現(xiàn)的. 這里就是關(guān)鍵, 消息到底發(fā)給誰(shuí)了
1. 從表象上來(lái)看, 因?yàn)槭强丶䦟?duì)消息產(chǎn)生了反應(yīng), 我們從感覺(jué)上就認(rèn)為消息是發(fā)給控件的, 控件上可能有一個(gè)消息隊(duì)列, 同時(shí)我們知道, 其實(shí)控件只是active obj, 它是由actor ui線程來(lái)驅(qū)動(dòng)的.
2. 但是我們從資料上可以輕松找到其實(shí)控件都沒(méi)有消息隊(duì)列, 消息隊(duì)列是和ui線程綁定在一起的:) 也就是說(shuō)一個(gè)actor一個(gè)隊(duì)列, 而不是說(shuō)一個(gè)active obj一個(gè)隊(duì)列.
我認(rèn)為這windows這個(gè)消息模型是很有借鑒價(jià)值的, 應(yīng)用到我們的設(shè)計(jì)中就是

可反應(yīng)的實(shí)體的定義
class activeobj {
void Active(msg m) {
processMsg(m);
}
}

actor的定義
class actor {
msgqueue mq;
void Loop() {
msg m = mq.popfront();
obj = FindObj(m.t) else goto yield();
obj.Active(m);
}
}
上述機(jī)制看上去又再一次的落入任務(wù)和線程綁定的模式中, 我們還是要再次研究, 一個(gè)游戲世界中, 只有一個(gè)時(shí)間軸, 如果說(shuō)每個(gè)消息都有一個(gè)時(shí)間戳的話, 那么它們應(yīng)該是"先來(lái)后到"的關(guān)系, 因?yàn)槲覀円WC消息有序. 所以, 我們不能使用一個(gè)actor一個(gè)隊(duì)列的方式, 消息隊(duì)列必須是全局的, 然后又幾個(gè)actor監(jiān)視這個(gè)隊(duì)列, 一旦有消息進(jìn)入的話, 就有一個(gè)actor會(huì)取到它并去處理. 為了驗(yàn)證我們的想法, 我在現(xiàn)實(shí)中找到了這樣實(shí)現(xiàn)的模型, 就是目前windows下最高效的IO模型完成端口, 完成端口的完成隊(duì)列就相當(dāng)于這里的消息隊(duì)列, 而actor就是線程池, 每個(gè)actor都企圖從完成隊(duì)列中取一個(gè)任務(wù)來(lái)執(zhí)行. 這和我們的想法是非常類(lèi)似的. 所以再次修改代碼:

可反應(yīng)的實(shí)體的定義
class activeobj {
void Active(msg m) {
processMsg(m);
}
}

定義一個(gè)全局的消息隊(duì)列
msgqueue mq;
mqlocal ml;

actor的定義
class actor {
void Loop() {
ml.lock();
msg m = mq.poptop() else goto yield();
ml.unlock();
obj = FIndObj(m);
obj->Active(m);
}
}
上面就是一個(gè)可選的方案, 首先它分?jǐn)偭擞?jì)算量, 計(jì)算量在msgqueue中存著, 真正的處理邏輯是在activeobj中, 而actor驅(qū)動(dòng)activeobj來(lái)執(zhí)行msgqueue中的消息的處理. 從設(shè)計(jì)的角度來(lái)說(shuō), 做到了職責(zé)分離. 而前面的設(shè)計(jì)中, msgqueue不是和activeobj綁定在一起, 就是和actor綁定在一起, 所以總是有一些問(wèn)題, 看來(lái)還是大牛們說(shuō)的對(duì), 每個(gè)概念都單獨(dú)表示, 然后通過(guò)組合把它們聯(lián)系起來(lái).
上面的這個(gè)方案好么? 首先, 我們的游戲中, 時(shí)序是非常重要的, 我們總是期望先到的消息能夠先處理[因?yàn)樗犬a(chǎn)生], 所以必須有一個(gè)消息排隊(duì)的地方, 所以有一個(gè)全局隊(duì)列是很重要的.其次就是, 我們不期望發(fā)生一個(gè)線程很忙, 另一個(gè)很閑的情況, 使用全局msg隊(duì)列就可以達(dá)到收集任務(wù), 管理任務(wù), 分配任務(wù)的效果, 上面這種模式就可以在大部分情況下平均分?jǐn)傆?jì)算量.

總結(jié)
上面簡(jiǎn)單介紹了一個(gè)多線程方案, 我并不是直接的給出了答案, 而是記錄了我在思考這個(gè)問(wèn)題的過(guò)程中遇到的各種問(wèn)題, 和如何解決這些問(wèn)題的思路(只能說(shuō)是思路:), 我認(rèn)為其中最重要的部分就是:
1. 抽象應(yīng)該是源于生活的, 不是空想的.
2. 對(duì)系統(tǒng)的看法: 一個(gè)系統(tǒng)之所以被劃分成為一個(gè)系統(tǒng), 是因?yàn)樵谙到y(tǒng)中的成員的交互和聯(lián)系頻率要遠(yuǎn)遠(yuǎn)大于和系統(tǒng)外實(shí)體的交互和聯(lián)系.
3. 各個(gè)系統(tǒng)不直接交互, 如果必須交互, 請(qǐng)一定走M(jìn)SG
4. MSG應(yīng)該維持時(shí)序性, 我這里使用的是全局MSG隊(duì)列來(lái)保證時(shí)序性.
在文中討論到最后的方案中, 任然存在著一些問(wèn)題, 比如說(shuō)在這種方案下, 全局的MSG隊(duì)列就是唯一一個(gè)全局且高競(jìng)爭(zhēng)數(shù)據(jù), 這里鎖的互斥是高發(fā)的, 所以在選擇鎖的時(shí)候需要斟酌等等, 希望能有所幫助, 歡迎大家提出更好的解決方案, 建設(shè)性的交流總是有益的:)

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門(mén)評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(0)

    昵稱(chēng):
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)