【golang】Go 效能最佳化技巧

來源:互聯網
上載者:User


一. array與slice

對於一些初學者,自知道 Go 裡面的 array 以 pass-by-value 方式傳遞後,就莫名地引起 “恐慌”。外加諸多文章未作說明,就建議用 slice 代替 array,企圖避免資料拷貝,提升效能。實際上,此做法有待商榷。某些時候怕會適得其反,倒造成不必要的效能損失。

用個簡單的樣本說明。

package mainimport ("fmt")const capacity = 1024func array() [capacity]int {var d [capacity]intfor i := 0; i < len(d); i++ {d[i] = 1}return d}func slice() []int {d := make([]int, capacity)for i := 0; i < len(d); i++ {d[i] = 1}return d}func main() {fmt.Println(array())fmt.Println(slice())}

代碼很簡單,兩個函數分別返回 “內容相同” 的 array 和 slice。為避免編譯器最佳化,特填充了全部資料,以類比 “真實” 資料複製行為。接下來,看看效能測試對比。

package mainimport ("testing")func BenchmarkArray(b *testing.B) {for i := 0; i < b.N; i++ {_ = array()}}func BenchmarkSlice(b *testing.B) {for i := 0; i < b.N; i++ {_ = slice()}}


這結果怕是顛覆了最初認知。array 非但擁有更好的效能,還避免了堆記憶體配置,也就是說減輕了 GC 壓力。為什麼會這樣。

熟悉彙編的,怕是很容易看出來。函數 array 傳回值的複製只需用 "CX + REP" 指令就可完成。


整個 array 函數完全在棧上完成,而 slice 函數則需執行 makeslice,繼而在堆上分配記憶體,這就是問題所在。

對於一些短小的對象,複製成本遠小於在堆上分配和回收操作。 Go Proverbs: A little copying is better than a little dependency.



二. defer

編譯器通過 runtime.deferproc “註冊” 延遲調用,除目標函數地址外,還會複製相關參數(包括 receiver)。在函數返回前,執行runtime.deferreturn 提取相關資訊執行延遲調用。這其中的代價自然不是普通函數調用一條 CALL 指令所能比擬的。


解決方案麼,要麼去掉 f.close 前的 defer,要麼將內層處理邏輯重構為獨立函數(比如匿名函數調用)。






相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.