Go語(yǔ)言高效編程的3個(gè)技巧總結(jié)
不要使用Logrus
這其實(shí)和泛型有關(guān)。因?yàn)镚o語(yǔ)言是一門強(qiáng)類型的靜態(tài)語(yǔ)言,所以你不可能像NodeJS或者PHP那樣繞過(guò)數(shù)據(jù)類型。那如果我們還需要使用通用的類型怎么辦呢?比如像Loger,或者ORM,因?yàn)橹挥惺褂昧送ㄓ玫念愋停拍芫帉懗鐾ㄓ玫拇a,不然每個(gè)都要寫一次。
最終,我們只能用反射。而 Logrus 大量使用反射,這導(dǎo)致大量分配計(jì)數(shù)。雖然通常不是一個(gè)大問(wèn)題(取決于代碼),但性能很重要,尤其是在大規(guī)模、高并發(fā)的項(xiàng)目中。雖然這聽(tīng)起來(lái)像是一個(gè)非常小的優(yōu)化,但避免反射很重要。如果你看到一些可以不考慮類型而使用結(jié)構(gòu)的代碼,它會(huì)使用反射并且會(huì)對(duì)性能產(chǎn)生影響。
例如,Logrus 并不關(guān)心類型,但顯然 Go 需要知道(最終)。Logrus 怎么辦呢?使用反射來(lái)檢測(cè)類型,這是開(kāi)銷。
log.WithFields(log.Fields{<!--{C}%3C!%2D%2D%20%2D%2D%3E--> “animal”: myWhatever, }).Info(“A walrus appears”)
所以我會(huì)更喜歡zerolog,當(dāng)然zap也不錯(cuò)。兩者都宣稱零分配,這也是我們希望的,因?yàn)樗鼈兊男阅苡绊懽钚 ?/p>
不要使用encoding/json
當(dāng)我們需要一個(gè)功能、函數(shù)的時(shí)候,很多人都建議使用標(biāo)準(zhǔn)庫(kù)。但是標(biāo)準(zhǔn)庫(kù)中的encoding/json模塊是個(gè)例外。其實(shí)也和上面的例子一樣,encoding/json使用反射,這會(huì)導(dǎo)致性能不高,并且在編寫返回 json 響應(yīng)的 API 、或者微服務(wù)時(shí)會(huì)造成損失。
比如你可以使用 Easyjson,它很簡(jiǎn)單,也很高效,它是使用代碼生成器來(lái)創(chuàng)建將結(jié)構(gòu)轉(zhuǎn)換為 json 所需的代碼,以最大限度地減少分配。這是一個(gè)手動(dòng)構(gòu)建步驟,很煩人。有趣的是json-iterator也使用反射,但速度明顯更快,我懷疑是黑魔法。
盡可能不要在goroutine中使用閉包
比如,下面這個(gè)示例代碼:
for i:=0;i<10;i++ { go func() { fmt.Println(i) }() }
大多數(shù)人可能期望這會(huì)打印數(shù)字 0 到 9,就像將任務(wù)委托給 goroutine 時(shí)那樣。
但是實(shí)際結(jié)果:根據(jù)系統(tǒng),你將得到一兩個(gè)數(shù)字和許多 10。
為什么會(huì)這樣?閉包可以訪問(wèn)父作用域,因此可以直接使用變量。盡管更新的 linters 可能會(huì)警告你“變量閉包捕獲”,但并不會(huì)要求你重新聲明該變量。
Go 的性能名聲很大程度上歸功于執(zhí)行的運(yùn)行時(shí)優(yōu)化,它嘗試“猜測(cè)”你想要做什么并優(yōu)化某些執(zhí)行路徑。在此期間,它“捕獲”變量并以理論上最有效的方式將它們傳遞到需要它們的地方(例如,在完成一些非并發(fā)操作以釋放某些 CPU 上的分配之后)。這種情況下的結(jié)果是循環(huán)可能會(huì)啟動(dòng) goroutines,goroutines可能會(huì)在很晚之后從父作用域接收到 i 的值。不能保證在多次執(zhí)行此代碼時(shí)你會(huì)看到哪個(gè),可能是數(shù)字10,也可以是其他數(shù)字。
如果你出于某種原因確實(shí)使用了閉包,一定要傳遞變量i,就像對(duì)待每個(gè)函數(shù)一樣對(duì)待閉包。
總結(jié)
到此這篇關(guān)于Go語(yǔ)言高效編程的3個(gè)技巧總結(jié)的文章就介紹到這了,更多相關(guān)Go語(yǔ)言高效編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Go語(yǔ)言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例
這篇文章主要介紹了使用Go語(yǔ)言創(chuàng)建WebSocket服務(wù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Golang使用Gin創(chuàng)建Restful API的實(shí)現(xiàn)
本文主要介紹了Golang使用Gin創(chuàng)建Restful API的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01go語(yǔ)言在請(qǐng)求http時(shí)加入自定義http header的方法
這篇文章主要介紹了go語(yǔ)言在請(qǐng)求http時(shí)加入自定義http header的方法,實(shí)例分析了Go語(yǔ)言http請(qǐng)求的原理與操作技巧,需要的朋友可以參考下2015-03-03