Go語言本來就以輕量快速著稱,一位GitHub員工卻偶然發(fā)現(xiàn):
只改變一個字符的位置,能把一段代碼運(yùn)行速度提高足足42%。
簡直就像是……
這個簡單有效的技巧一經(jīng)發(fā)布,就引來眾多程序員圍觀。
原作者自己也調(diào)侃,一般這種情況都是事先犯了個愚蠢的錯誤,后面才能提升這么大。
不過順著這個思路發(fā)現(xiàn)有人發(fā)現(xiàn),就連Go開發(fā)團(tuán)隊的核心人物Russ Cox都在標(biāo)準(zhǔn)庫中犯過同樣的錯誤。
什么樣的錯誤?
發(fā)現(xiàn)這個問題的Harry在大型程序員交友平臺GitHub工作。
他在開發(fā)一個把GitHub倉庫中每個文件的所有者列出來的小工具。
功能很簡單,就是根據(jù)CODEOWNERS文件中定義的規(guī)則匹配,寫在越下面的規(guī)則優(yōu)先級越高。
原理也很簡單,就是從后往前一條一條處理,匹配到了就停止。
但就是這樣一個簡單的程序卻出現(xiàn)了性能問題,處理中等大小的倉庫就很慢了。
他打印出火焰圖,發(fā)現(xiàn)大部分時間都花在了Go語言的正則表達(dá)式引擎中。
另外在內(nèi)存動態(tài)分配malloc和垃圾回收gc上面的花費(fèi)也值得注意。
要減少malloc的時間,就需要用到Go語言的逃逸分析(Escape Analysis)了。
簡單來說,就是盡量把變量分配到棧上,讓編譯器自動管理內(nèi)存的釋放。
只有在“逃逸”也就是變量的作用域超出所在的棧時,才把變量分配到堆上,減輕運(yùn)行時GC的壓力。
在這次的程序中,Harry確定了逃逸的變量是rule這個結(jié)構(gòu)體(struct)。
但問題是,rule存儲在RuleSet這個切片(slice)里,按Go語言的規(guī)則可以確信他已經(jīng)在堆中了。
再分析一下代碼,發(fā)現(xiàn)在給rule賦值的時候?qū)嶋H上是做了一次不必要的拷貝,后面用“&”取地址時候創(chuàng)建了一個逃逸的指針指向它的副本。
最后解決辦法也很容易想出,只需要把&移動到上面。
這樣就引用了切片中的結(jié)構(gòu)體,避免了拷貝。
如何徹底避免?
在熱議中,有網(wǎng)友分享了自己是怎么避免出現(xiàn)這個問題的。
對于每個結(jié)構(gòu)體,把它看作純值或純指針,壓根就不去使用&這種取地址的操作,避免隱式的內(nèi)存分配。
如果你想要深入理解這個問題,也有人貼心的給出了需要提前了解的一些背景知識。
最后有人指出,Rust語言為避免這個問題,直接規(guī)定必須顯式操作才能拷貝一個數(shù)據(jù)結(jié)構(gòu)。
當(dāng)你不習(xí)慣的時候這規(guī)定煩得要命,但是總的來看還是值得。
方便or規(guī)范,你更傾向于哪種做法?
審核編輯 :李倩
-
代碼
+關(guān)注
關(guān)注
30文章
4797瀏覽量
68707 -
go語言
+關(guān)注
關(guān)注
1文章
158瀏覽量
9053
原文標(biāo)題:只改變一個字符使 Go 程序提速 42%
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論