go語(yǔ)言之-cgo

最近由于工作需要,由于選型幀同步匆赃,服務(wù)器需要跑客戶端代碼淤毛,我們后端是go語(yǔ)言,客戶端是c++

記錄一下在這個(gè)過程中遇到的問題炸庞,和解決問題思路钱床。與最后的成果。

  1. 首先學(xué)習(xí)cgo
    學(xué)習(xí)一個(gè)組件很簡(jiǎn)單埠居,學(xué)習(xí)cgo的基礎(chǔ)就可以查牌,既然我是使用,并不需要研究cgo的多么深滥壕。

cgo需要在go文件中加入import "C",并且需要在import "C"上面緊貼著寫上自己的c代碼

例如

package main

/*
#cgo LDFLAGS: -L -lc -ldl
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include "library.h" //非標(biāo)準(zhǔn)c頭文件纸颜,所以用引號(hào)
*/
import "C"

這里記錄一下 #cgo LDFLAGS: 的作用吧,這個(gè)的作用就是設(shè)置gcc的一些參數(shù)绎橘。-L和gcc中的LD_LIBRARY是一樣的東西胁孙,-l后面接上動(dòng)態(tài)庫(kù)。
假如說称鳞,在同級(jí)目錄下涮较,有一個(gè)libaaa.so 那么我需要這樣設(shè)置

#cgo LDFLAGS: -L ./ -laaa 

這里我加上了-ldl 我要加載操作系統(tǒng)中某些庫(kù),因?yàn)楹竺嫖矣玫搅薲lopen動(dòng)態(tài)加載so庫(kù)
如果你出現(xiàn)過dlopen' ‘dlsym’ undefined reference 你可以加上-ldl 如果過你還沒找到冈止,你就去找出現(xiàn)沒找到的包所在的系統(tǒng)位置狂票,然后查看系統(tǒng)環(huán)境變量LD_LIBRARY_PATH里面是否有當(dāng)前目錄就可以。(-ldl要放在最后面)

接下來(lái)熙暴,我們就要用了闺属,我寫了一個(gè)library.h與我的go文件相同的位置


image.png

這樣,我直接寫#include"文件名"就可以了

在這里簡(jiǎn)單介紹下cgo的代碼使用

cgo封裝了c中所有結(jié)構(gòu)體周霉。有很多文章都說過他的類型轉(zhuǎn)換問題了掂器。
其實(shí)很簡(jiǎn)單,直接C.對(duì)應(yīng)的類型就可以
例如

// cgo.go
    cs := C.CString("XXX")
    defer C.free(unsafe.Pointer(cs))
    C.InitConfigData( cs)
// library.c
void Init(char* resPath)
{  
    俱箱。国瓮。。
}

這樣是直接可以調(diào)用的
這里需要注意的是狞谱,go的內(nèi)存是有垃圾回收的巍膘,但是并不回收c的內(nèi)存屬性。所以芋簿,這里所有的入?yún)⒈仨毷荂的類型峡懈。
而且初始化完了必須要加defer()自己手動(dòng)釋放。

cgo調(diào)用c++

這里有很多方式調(diào)用与斤,我選用的是cgo-->c-->c++的路線
因?yàn)榉究担腸++代碼是動(dòng)態(tài)庫(kù)荚恶,由于客戶端程序員不給我封裝c的 .h文件,(因?yàn)楣ぷ髁刻罅字В昧撕芏郼++std庫(kù)的東西谒撼,所以要全部封出來(lái)還需要很大的代碼量)
我自己寫的這個(gè)library.c就是從程序里依賴c++動(dòng)態(tài)庫(kù),動(dòng)態(tài)加載到內(nèi)存中雾狈。
具體不詳細(xì)寫了廓潜,直接上代碼

typedef  struct tagUServerMgr* (*GetInstanceFunc)();
static GetInstanceFunc getInstance = NULL;

// 省略好多行

        //打開動(dòng)態(tài)鏈接庫(kù)
    handle = dlopen(lib_path, RTLD_NOW);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }
    //清除之前存在的錯(cuò)誤
    dlerror();

    getInstance = (GetInstanceFunc)dlsym(handle, "GetInstance");
    if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }
    if (getInstance==NULL){
        exit(EXIT_FAILURE);
    }
// 省略好多行

這里代碼,我就是用RTLD_NOW的方式加載動(dòng)態(tài)庫(kù)善榛。然后獲取里面的getInstance方法辩蛋。之后,我go代碼直接可以C.GetInstance()就可以調(diào)用移盆。我個(gè)人覺得挺方便的悼院。

cgo的性能測(cè)試,

在客戶端跑幀的時(shí)候咒循,測(cè)試過cgo的性能据途。
從go程序調(diào)用,到c方法入口叙甸,期間傳基礎(chǔ)數(shù)據(jù)類型颖医。測(cè)試下來(lái)平均調(diào)用一次消耗0.3ms。如果你的業(yè)務(wù)不需要1毫秒一下的效率裆蒸,可以放心大膽的使用熔萧。對(duì)復(fù)雜數(shù)據(jù)類型解析,會(huì)慢光戈,但是沒有明顯變化,在我的業(yè)務(wù)下遂赠,轉(zhuǎn)換一個(gè)1kb的數(shù)據(jù)久妆。大約在0.5ms調(diào)用一次,包括入?yún)⒊鰠r(shí)間跷睦。

cgo遇到的問題

問題:在測(cè)試中發(fā)現(xiàn)筷弦,當(dāng)我go程序sleep后,cgo調(diào)用的c方法效率會(huì)明顯下降抑诸。但是如果不sleep會(huì)效率能夠達(dá)到需求烂琴。由于,業(yè)務(wù)要求是幀同步蜕乡,所以我用sleep來(lái)卡ms時(shí)間
(經(jīng)過了與客戶端半天的爭(zhēng)吵奸绷,客戶端寫了個(gè)自測(cè)程序,發(fā)現(xiàn)沒有問題所以我懷疑是我這邊的問題)
解決思路:可能是time.sleep的操作层玲。
解決:更換成為time.tinker等time下其他的時(shí)間控制
結(jié)果:相同結(jié)果号醉,只要每次調(diào)用中間sleep30ms 就會(huì)變慢反症。
解決思路:如果只sleep1ms會(huì)不會(huì)變慢。
解決:分別測(cè)試了1ms畔派,2ms铅碍,5ms
結(jié)果:發(fā)現(xiàn)1ms也會(huì)變慢。問題清晰了許多线椰,似乎就是sleep的問題
解決思路:如果用卡時(shí)間戳的概念胞谈,模擬sleep的睡的時(shí)間是否能夠滿足需求,不斷地for循環(huán)憨愉,每次都判斷是否過了30ms烦绳,過了,就執(zhí)行一次莱衩,沒過就等下一次判斷爵嗅。
解決:寫了個(gè)for的例子。測(cè)試下
結(jié)果:發(fā)現(xiàn)的確快了笨蚁,是time.sleep的問題

  • 目前為止:代碼層面已經(jīng)解決了睹晒,可能之后業(yè)務(wù)中也是使用for但是for有好幾個(gè)不好的地方,
    1. 只要跑就是cpu打滿括细。在go中伪很,會(huì)默認(rèn)分配1個(gè)攜程可以沾滿1個(gè)cpu。
    2. 會(huì)出現(xiàn)很多空轉(zhuǎn)for奋单,因?yàn)槲颐看握{(diào)用幀更新最小是1ms锉试,如果一個(gè)cpu一直在工作,那么最多處理1000幀更新請(qǐng)求览濒,那么一個(gè)玩家是一秒需要跑30幀呆盖,在這33個(gè)玩家正正好好不沖突的情況下,全部沒有網(wǎng)絡(luò)延遲贷笛,沒有io限制应又,等等,1個(gè)cpu最多支持33個(gè)玩家同時(shí)玩乏苦。但是這33不是不沖突的情況下株扛,假如說,某幾納秒所有人都在等下一個(gè)幀時(shí)間到來(lái)汇荐,那么cpu就會(huì)空轉(zhuǎn)洞就。浪費(fèi)cpu資源。
    3. 1個(gè)玩家也會(huì)沾滿cpu所有資源

這些問題掀淘,可能留到后期優(yōu)化了旬蟋,各位有什么好的建議可以可以私信我。

接下來(lái)查看go中的sleep是否對(duì)接下來(lái)的程序執(zhí)行效率會(huì)變慢革娄。

查看sleep的源碼發(fā)現(xiàn)咖为,sleep是采用系統(tǒng)中斷來(lái)喚醒睡著的程序秕狰。sleep這行代碼,做了比較重要的事情是

  1. 更改了系統(tǒng)終端表躁染,操作系統(tǒng)會(huì)不斷查看系統(tǒng)終端表來(lái)發(fā)中斷鸣哀,從而喚醒任務(wù)
  2. 把當(dāng)前線程從cpu任務(wù)隊(duì)列拿出,意思是當(dāng)前線程資源會(huì)從cpu中拿走吞彤。這也就是為什么sleep完了后會(huì)執(zhí)行變慢我衬,可能會(huì)有加載數(shù)據(jù)這段時(shí)間吧。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末饰恕,一起剝皮案震驚了整個(gè)濱河市挠羔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌埋嵌,老刑警劉巖破加,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異雹嗦,居然都是意外死亡范舀,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門了罪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锭环,“玉大人,你說我怎么就攤上這事泊藕「ū纾” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵娃圆,是天一觀的道長(zhǎng)玫锋。 經(jīng)常有香客問我,道長(zhǎng)讼呢,這世上最難降的妖魔是什么撩鹿? 我笑而不...
    開封第一講書人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮吝岭,結(jié)果婚禮上三痰,老公的妹妹穿的比我還像新娘吧寺。我一直安慰自己窜管,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開白布稚机。 她就那樣靜靜地躺著幕帆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赖条。 梳的紋絲不亂的頭發(fā)上失乾,一...
    開封第一講書人閱讀 52,696評(píng)論 1 312
  • 那天常熙,我揣著相機(jī)與錄音,去河邊找鬼碱茁。 笑死裸卫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的纽竣。 我是一名探鬼主播墓贿,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蜓氨!你這毒婦竟也來(lái)了聋袋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤穴吹,失蹤者是張志新(化名)和其女友劉穎幽勒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體港令,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啥容,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缠借。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片干毅。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泼返,靈堂內(nèi)的尸體忽然破棺而出硝逢,到底是詐尸還是另有隱情,我是刑警寧澤绅喉,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布渠鸽,位于F島的核電站,受9級(jí)特大地震影響柴罐,放射性物質(zhì)發(fā)生泄漏徽缚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一革屠、第九天 我趴在偏房一處隱蔽的房頂上張望凿试。 院中可真熱鬧,春花似錦似芝、人聲如沸那婉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)详炬。三九已至,卻和暖如春寞奸,著一層夾襖步出監(jiān)牢的瞬間呛谜,已是汗流浹背在跳。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留隐岛,地道東北人猫妙。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像聚凹,于是被迫代替她去往敵國(guó)和親吐咳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361