Go程序提速42%,只需改變一個字符
Go開發(fā)團隊的核心人物Russ Cox都在標準庫中犯過同樣的錯誤
夢晨 發(fā)自 凹非寺量子位 | 公眾號 QbitAI
Go語言本來就以輕量快速著稱,一位GitHub員工卻偶然發(fā)現(xiàn):
只改變一個字符的位置,能把一段代碼運行速度提高足足42%。
簡直就像是……
這個簡單有效的技巧一經(jīng)發(fā)布,就引來眾多程序員圍觀。
原作者自己也調(diào)侃,一般這種情況都是事先犯了個愚蠢的錯誤,后面才能提升這么大。
不過順著這個思路發(fā)現(xiàn)有人發(fā)現(xiàn),就連Go開發(fā)團隊的核心人物Russ Cox都在標準庫中犯過同樣的錯誤。
什么樣的錯誤?
發(fā)現(xiàn)這個問題的Harry在大型程序員交友平臺GitHub工作。
他在開發(fā)一個把GitHub倉庫中每個文件的所有者列出來的小工具。
功能很簡單,就是根據(jù)CODEOWNERS文件中定義的規(guī)則匹配,寫在越下面的規(guī)則優(yōu)先級越高。
原理也很簡單,就是從后往前一條一條處理,匹配到了就停止。
但就是這樣一個簡單的程序卻出現(xiàn)了性能問題,處理中等大小的倉庫就很慢了。
他打印出火焰圖,發(fā)現(xiàn)大部分時間都花在了Go語言的正則表達式引擎中。
另外在內(nèi)存動態(tài)分配malloc和垃圾回收gc上面的花費也值得注意。
要減少malloc的時間,就需要用到Go語言的逃逸分析(Escape Analysis)了。
簡單來說,就是盡量把變量分配到棧上,讓編譯器自動管理內(nèi)存的釋放。
只有在“逃逸”也就是變量的作用域超出所在的棧時,才把變量分配到堆上,減輕運行時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)。
當你不習慣的時候這規(guī)定煩得要命,但是總的來看還是值得。
方便or規(guī)范,你更傾向于哪種做法?
參考鏈接:
[1]https://hmarr.com/blog/go-allocation-hunting/
[2]https://news.ycombinator.com/item?id=33594676
- 字節(jié)突然開源Seed-OSS,512K上下文主流4倍長度,推理能力刷紀錄2025-08-21
- “現(xiàn)在讀AI博士已經(jīng)太晚了”2025-08-19
- 谷歌AI攻克亞洲語言難題,2300種語言數(shù)字化計劃正在推進2025-08-18
- AMD蘇姿豐公開懟扎克伯格!反對1億年薪挖人,使命感比鈔票更重要2025-08-18