Go語(yǔ)言本來(lái)就以輕量快速著稱,一位GitHub員工卻偶然發(fā)現(xiàn):
只改變一個(gè)字符的位置,能把一段代碼運(yùn)行速度提高足足42%。
簡(jiǎn)直就像是……
這個(gè)簡(jiǎn)單有效的技巧一經(jīng)發(fā)布,就引來(lái)眾多程序員圍觀。
原作者自己也調(diào)侃,一般這種情況都是事先犯了個(gè)愚蠢的錯(cuò)誤,后面才能提升這么大。
不過(guò)順著這個(gè)思路發(fā)現(xiàn)有人發(fā)現(xiàn),就連Go開(kāi)發(fā)團(tuán)隊(duì)的核心人物Russ Cox都在標(biāo)準(zhǔn)庫(kù)中犯過(guò)同樣的錯(cuò)誤。
什么樣的錯(cuò)誤?
發(fā)現(xiàn)這個(gè)問(wèn)題的Harry在大型程序員交友平臺(tái)GitHub工作。
他在開(kāi)發(fā)一個(gè)把GitHub倉(cāng)庫(kù)中每個(gè)文件的所有者列出來(lái)的小工具。
功能很簡(jiǎn)單,就是根據(jù)CODEOWNERS文件中定義的規(guī)則匹配,寫(xiě)在越下面的規(guī)則優(yōu)先級(jí)越高。
原理也很簡(jiǎn)單,就是從后往前一條一條處理,匹配到了就停止。
但就是這樣一個(gè)簡(jiǎn)單的程序卻出現(xiàn)了性能問(wèn)題,處理中等大小的倉(cāng)庫(kù)就很慢了。
他打印出火焰圖,發(fā)現(xiàn)大部分時(shí)間都花在了Go語(yǔ)言的正則表達(dá)式引擎中。
另外在內(nèi)存動(dòng)態(tài)分配malloc和垃圾回收gc上面的花費(fèi)也值得注意。
要減少malloc的時(shí)間,就需要用到Go語(yǔ)言的逃逸分析(Escape Analysis)了。
簡(jiǎn)單來(lái)說(shuō),就是盡量把變量分配到棧上,讓編譯器自動(dòng)管理內(nèi)存的釋放。
只有在“逃逸”也就是變量的作用域超出所在的棧時(shí),才把變量分配到堆上,減輕運(yùn)行時(shí)GC的壓力。
在這次的程序中,Harry確定了逃逸的變量是rule這個(gè)結(jié)構(gòu)體(struct)。
但問(wèn)題是,rule存儲(chǔ)在RuleSet這個(gè)切片(slice)里,按Go語(yǔ)言的規(guī)則可以確信他已經(jīng)在堆中了。
再分析一下代碼,發(fā)現(xiàn)在給rule賦值的時(shí)候?qū)嶋H上是做了一次不必要的拷貝,后面用“&”取地址時(shí)候創(chuàng)建了一個(gè)逃逸的指針指向它的副本。
最后解決辦法也很容易想出,只需要把&移動(dòng)到上面。
這樣就引用了切片中的結(jié)構(gòu)體,避免了拷貝。
如何徹底避免?
在熱議中,有網(wǎng)友分享了自己是怎么避免出現(xiàn)這個(gè)問(wèn)題的。
對(duì)于每個(gè)結(jié)構(gòu)體,把它看作純值或純指針,壓根就不去使用&這種取地址的操作,避免隱式的內(nèi)存分配。
如果你想要深入理解這個(gè)問(wèn)題,也有人貼心的給出了需要提前了解的一些背景知識(shí)。
最后有人指出,Rust語(yǔ)言為避免這個(gè)問(wèn)題,直接規(guī)定必須顯式操作才能拷貝一個(gè)數(shù)據(jù)結(jié)構(gòu)。
當(dāng)你不習(xí)慣的時(shí)候這規(guī)定煩得要命,但是總的來(lái)看還是值得。
方便or規(guī)范,你更傾向于哪種做法?
審核編輯 :李倩
-
代碼
+關(guān)注
關(guān)注
30文章
4837瀏覽量
69123 -
go語(yǔ)言
+關(guān)注
關(guān)注
1文章
158瀏覽量
9094
原文標(biāo)題:只改變一個(gè)字符使 Go 程序提速 42%
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
字符串反轉(zhuǎn)的實(shí)現(xiàn)方式
飛凌嵌入式ElfBoard ELF 1板卡-提示程序之提示腳本continue.sh
stm32/gd32 wifi模塊通信異常問(wèn)題
鴻蒙原生應(yīng)用元服務(wù)開(kāi)發(fā)-倉(cāng)頡基礎(chǔ)數(shù)據(jù)類(lèi)型字符類(lèi)型
MATLAB(5)--字符串處理
飛凌嵌入式ElfBoard ELF 1板卡-shell腳本編寫(xiě)之傳參
vim的操作方式有哪幾種
vim的三種工作模式有哪些
請(qǐng)問(wèn)AT命令可以支持多少個(gè)字符?
使用CIPDOMAIN命令時(shí),解析長(zhǎng)度為64個(gè)字符或更大的DNS名稱失敗了,為什么?
FX3在安卓系統(tǒng)上顯示為\"DDC\",有什么辦法可以定義這個(gè)字符串嗎?
JDY-08藍(lán)牙模塊AT指令響應(yīng)只能接收到第一個(gè)字符是怎么回事?
如何提取串口接收字符串?dāng)?shù)組里的某個(gè)字符串?
深入解析西門(mén)子博途文本塊接口的結(jié)構(gòu)與功能
![深入解析西門(mén)子博途文本塊接口的結(jié)構(gòu)與功能](https://file1.elecfans.com/web2/M00/C8/CF/wKgaomYXWBGAL_6_AAA6IvnjCOI990.png)
評(píng)論