讓 C 程序更高效的 10 個(gè)建議

面對的問題

從事開發(fā)工程中季春,遇到過不少問題馒胆,很多時(shí)候由于時(shí)間緊迫徙菠,沒有使用優(yōu)雅的方案讯沈。在跟業(yè)內(nèi)的一些朋友交流過程中,我也意識到有些問題是大家都存在的。簡單列舉如下:

多線程與并發(fā)

異步消息/接口調(diào)用

消息的序列化與Reflection

性能優(yōu)化

單元測試

多線程與并發(fā)

現(xiàn)在是多核時(shí)代缺狠,并發(fā)才能實(shí)現(xiàn)更高的吞吐量问慎、更快的響應(yīng),但也是把雙刃劍挤茄∪绲穑總結(jié)如下幾個(gè)用法:

多線程+顯示鎖;接口是被多線程調(diào)用的穷劈,當(dāng)被調(diào)用時(shí)笼恰,顯示加鎖,再操作實(shí)體數(shù)據(jù)歇终。悲劇的是社证,工程師為了優(yōu)化會(huì)設(shè)計(jì)多個(gè)鎖,以減少鎖的粒度评凝,甚至有些地方使用了原子操作追葡。這些都為領(lǐng)域邏輯增加了額外的設(shè)計(jì)負(fù)擔(dān)。最壞的情況是會(huì)出現(xiàn)死鎖奕短。

多線程+任務(wù)隊(duì)列宜肉;接口被多線程調(diào)用,但請求會(huì)被暫存到任務(wù)隊(duì)列翎碑,而任務(wù)隊(duì)列會(huì)被單線程不斷執(zhí)行谬返,典型生產(chǎn)者消費(fèi)者模式。它的并發(fā)在于不同的接口可以使用不同的任務(wù)隊(duì)列日杈。這也是我最常用的并發(fā)方式朱浴。

這是兩種最常見的多線程并發(fā),它們有個(gè)天生的缺陷——Scalability达椰。一個(gè)機(jī)器的性能總是有瓶頸的翰蠢。兩個(gè)場景的邏輯雖然由多個(gè)線程實(shí)現(xiàn)了并發(fā),但是運(yùn)算量十分有可能是一臺(tái)機(jī)器無法承載的啰劲。如果是多進(jìn)程并發(fā)梁沧,那么可以分布式把其部署到其他機(jī)器(也可部署在一臺(tái)機(jī)器)。所以多進(jìn)程并發(fā)比多線程并發(fā)更加Scalability蝇裤。另外采用多進(jìn)程后廷支,每個(gè)進(jìn)程單線程設(shè)計(jì),這樣的程序更加Simplicity栓辜。多進(jìn)程的其他優(yōu)點(diǎn)如解耦恋拍、模塊化、方便調(diào)試藕甩、方便重用等就不贅言了施敢。

異步消息/接口調(diào)用

提到分布式,就要說一下分布式的通訊技術(shù)。常用的方式如下:

類RPC僵娃;包括WebService概作、RPC、ICE等默怨,特點(diǎn)是遠(yuǎn)程同步調(diào)用讯榕。遠(yuǎn)程的接口和本地的接口非常相似。但是游戲服務(wù)器程序一般非常在意延遲和吞吐量匙睹,所以這些阻塞線程的同步遠(yuǎn)程調(diào)用方式并不常用愚屁。但是我們必須意識到他的優(yōu)點(diǎn),就是非常利于調(diào)用和測試痕檬。

全異步消息霎槐;當(dāng)調(diào)用遠(yuǎn)程接口的時(shí)候,異步發(fā)送請求消息谆棺,接口響應(yīng)后返回一個(gè)結(jié)果消息栽燕,調(diào)用方的回調(diào)函數(shù)處理結(jié)果消息繼續(xù)邏輯操作罕袋。所以有些邏輯就會(huì)被切割成ServiceStart和ServiceCallback兩段改淑。有時(shí)異步會(huì)講領(lǐng)域邏輯變得支離破碎。另外消息處理函數(shù)中一般會(huì)寫一坨的switch/case 處理不同的消息浴讯。最大的問題在于單元測試朵夏,這種情況傳統(tǒng)單元測試根本束手無策。

消息的序列化與Reflection

實(shí)現(xiàn)消息的序列化和反序列化的方式有很多榆纽,常見的有Struct仰猖、json、Protobuff等都有很成功的應(yīng)用奈籽。我個(gè)人傾向于使用輕量級的二進(jìn)制序列化饥侵,優(yōu)點(diǎn)是比較透明和高效,一切在掌握之中衣屏。在FFLIB 中實(shí)現(xiàn)了bin_encoder_t 和 bin_decoder_t 輕量級的消息序列化躏升,幾十行代碼而已。

性能優(yōu)化


有的網(wǎng)友提到profiler狼忱、cpuprofiler膨疏、callgrind等工具。這些工具我都使用過钻弄,說實(shí)話佃却,對于我來說,我太認(rèn)同它有很高的價(jià)值窘俺。第一他們只能用于開發(fā)測試階段饲帅,可以初步得到一些性能上參考數(shù)據(jù)。第二它們?nèi)绾螌?shí)現(xiàn)跟蹤人們無從得知。運(yùn)行其會(huì)使程序變慢洒闸,不能反映真實(shí)數(shù)據(jù)染坯。第三重要的是,開發(fā)測試階段性能和上線后的能一樣嗎丘逸?Impossible 单鹿!

關(guān)于性能,原則就是數(shù)據(jù)說話深纲,詳見博文仲锄,不在贅述。

單元測試

關(guān)于單元測試湃鹊,前邊已經(jīng)談?wù)摿艘恍┤搴啊S螒蚍?wù)器程序一般都比較龐大,但是不可思議的是币呵,鄙人從來沒見有項(xiàng)目(c++ 后臺(tái)架構(gòu)的)有完整單元測試的怀愧。由于存在著異步和多線程,傳統(tǒng)的單元測試框架無法勝任余赢,而開發(fā)支持異步的測試框架又是不現(xiàn)實(shí)的芯义。我們必須看到的是,傳統(tǒng)的單元測試框架已經(jīng)取得了非常大的成功妻柒。據(jù)我了解扛拨,使用web 架構(gòu)的游戲后臺(tái)已經(jīng)對于單元測試的使用已經(jīng)非常成熟,取得了極其好的效果举塔。所以我的思路是利用現(xiàn)有的單元測試框架绑警,將異步消息、多線程的架構(gòu)做出調(diào)整央渣。

已經(jīng)多次談?wù)搯卧獪y試了计盒。其實(shí)在開發(fā)FFLIB的思路很大程度來源于此,否則可能只是一個(gè)c++ 網(wǎng)絡(luò)庫而已芽丹。我決定嘗試去解決這個(gè)問題的時(shí)候北启,把FFLIB 定位于框架。

先來看一段非常簡單的單元測試的代碼 :

推薦C語言C++學(xué)習(xí)交流群:466572167

請?jiān)试S我對這行代碼做些解釋志衍,對Add函數(shù)輸入?yún)?shù)暖庄,驗(yàn)證返回值是否是預(yù)期的結(jié)果。這不就是單元測試的本質(zhì)嗎楼肪?在想一下我們異步發(fā)送消息的過程培廓,如果每個(gè)輸入消息約定一個(gè)結(jié)果消息包,每次發(fā)送請求時(shí)都綁定一個(gè)回調(diào)函數(shù)接收和驗(yàn)證結(jié)果消息包春叫。這樣的話就恰恰滿足了傳統(tǒng)單元測試的步驟了肩钠。最后還需解決一個(gè)問題泣港,Assert是不能處理異步的返回值的。幸運(yùn)的是价匠,future機(jī)制可以化異步為同步当纱。不了解future 模式的可以參考這里:

來看一下在FFLIB框架下遠(yuǎn)程調(diào)用echo 服務(wù)的示例:

當(dāng)需要調(diào)用遠(yuǎn)程接口時(shí),async_call(in, &lambda_t::callback); 異步調(diào)用必須綁定一個(gè)回調(diào)函數(shù)踩窖,回調(diào)函數(shù)接收結(jié)果消息坡氯,可以觸發(fā)后續(xù)操作。這樣的話洋腮,如果對echo 的遠(yuǎn)程接口做單元測試箫柳,可以這樣做:

推薦C語言C++學(xué)習(xí)交流群:466572167
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市啥供,隨后出現(xiàn)的幾起案子悯恍,更是在濱河造成了極大的恐慌,老刑警劉巖伙狐,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涮毫,死亡現(xiàn)場離奇詭異,居然都是意外死亡贷屎,警方通過查閱死者的電腦和手機(jī)罢防,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豫尽,“玉大人篙梢,你說我怎么就攤上這事顷帖∶谰桑” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵贬墩,是天一觀的道長榴嗅。 經(jīng)常有香客問我,道長陶舞,這世上最難降的妖魔是什么嗽测? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮肿孵,結(jié)果婚禮上唠粥,老公的妹妹穿的比我還像新娘。我一直安慰自己停做,他們只是感情好晤愧,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛉腌,像睡著了一般官份。 火紅的嫁衣襯著肌膚如雪只厘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天舅巷,我揣著相機(jī)與錄音羔味,去河邊找鬼。 笑死钠右,一個(gè)胖子當(dāng)著我的面吹牛赋元,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播飒房,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼们陆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了情屹?” 一聲冷哼從身側(cè)響起坪仇,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎垃你,沒想到半個(gè)月后椅文,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡惜颇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年皆刺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凌摄。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡羡蛾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锨亏,到底是詐尸還是另有隱情痴怨,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布器予,位于F島的核電站浪藻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏乾翔。R本人自食惡果不足惜爱葵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望反浓。 院中可真熱鬧萌丈,春花似錦、人聲如沸雷则。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽巧婶。三九已至乾颁,卻和暖如春涂乌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背英岭。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工湾盒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诅妹。 一個(gè)月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓罚勾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吭狡。 傳聞我的和親對象是個(gè)殘疾皇子尖殃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,113評論 1 32
  • 在一個(gè)方法內(nèi)部定義的變量都存儲(chǔ)在棧中,當(dāng)這個(gè)函數(shù)運(yùn)行結(jié)束后划煮,其對應(yīng)的棧就會(huì)被回收送丰,此時(shí),在其方法體中定義的變量將不...
    Y了個(gè)J閱讀 4,420評論 1 14
  • 我想大部份朋友都可能有過向他人借錢或者他人向你借錢的經(jīng)歷登失,雖說借錢只是生活當(dāng)中的一件普通小事,但是否也偶爾會(huì)給我們...
    木春先生閱讀 928評論 0 1
  • 雁去春回何有悔挖炬, 似道別愁更傷悲揽浙。 ...
    檸檬不萌只是酸60660閱讀 170評論 1 0
  • 永遠(yuǎn)的上班族O谙铩?是你希望的嗎空闲?這個(gè)還是最理想的打算令杈,就怕做了個(gè)5走敌,6年的工薪階層碴倾,后來卻發(fā)現(xiàn)自己之前積累的工作經(jīng)驗(yàn)...
    4陳雨澤4閱讀 194評論 0 0