Golang 數據結構性能優化實踐

僅僅通過對 struct 字段重新排序,優化內存對齊方式,就可以獲得明顯的內存和執行效率提升。原文: How to Speed Up Your Struct in Golang[1]

如果你有 Golang 開發經驗,一定定義過 struct 類型。

但可能你不知道,通過簡單的重新排序 struct 字段,可以極大提高 Go 程序的速度和內存使用效率!

是不是難以置信?我們一起來看一下吧!

簡單 Demo

type BadStruct struct {
 age         uint8
 passportNum uint64
 siblings    uint16
}

type GoodStruct struct {
 age         uint8
 siblings    uint16
 passportNum uint64
}

在上面的代碼片段中,我們創建了兩個具有相同字段的結構體。然後編寫一個簡單程序分別輸出其內存使用情況。

// Output
Bad struct is 24 bytes long
Good struct is 16 bytes long

如你所見,它們在內存使用方面並不一樣。

是什麼原因導致兩個完全相似的 struct 消耗的內存不同?

答案在於數據在計算機內存中的排列方式。

簡而言之,數據結構對齊。

數據結構對齊

CPU 以字 (word) 爲單位讀取數據,而不是字節(byte)。

64 位系統中,一個 word 是 8 個字節,而 32 位系統中,一個 word 是 4 個字節。

簡而言之,CPU 以其字長的倍數讀取內存地址。

想象一下,在 64 位系統中,爲了獲取變量passportNum,CPU 需要兩個週期來訪問數據。

第一個週期將獲取內存的 0 到 7 字節,下一個週期獲取其餘內存字節。

把它想象成一個筆記本,每頁只能存儲一個字大小的數據 (在本例中爲 8 字節)。如果passportNum分散在兩個頁,則需要兩次讀取才能檢索到完整的數據。

非常低效。

因此需要數據結構對齊,讓計算機將數據存儲在等於數據大小倍數的地址上。

4 字節數據只能從內存地址 0 或 4 開始

例如,2 字節數據可以存儲在內存 0、2 或 4 中,而 4 字節數據可以存儲在內存 0、4 或 8 中。

通過簡單的對齊數據,計算機確保可以在一個 CPU 週期內檢索到變量passportNum

數據結構填充

填充是實現數據對齊的關鍵。

計算機通過在數據結構之間填充額外的字節,從而對齊字段。

這就是額外內存的來源!

我們來回顧一下BadStructGoodStruct

GoodStruct消耗更少的內存,僅僅因爲與BadStruct相比,其 struct 字段順序更合理。

由於填充,兩個 13 字節的數據結構分別變成了 16 字節和 24 字節。

因此,可以僅僅通過對 struct 字段重新排序來節省額外的內存!

這種優化爲什麼重要?

問題來了,你爲什麼要關心這個?

兩個方面,速度和內存使用。

我們做一個簡單的基準測試來證明!

func traverseGoodStruct() uint16 {
 var arbitraryNum uint16
  
 for _, goodStruct := range GoodStructArr {
  arbitraryNum += goodStruct.siblings
 }
  
 return arbitraryNum
}

func traverseBadStruct() uint16 {
 var arbitraryNum uint16
  
 for _, badStruct := range BadStructArr {
  arbitraryNum += badStruct.siblings
 }
  
 return arbitraryNum
}

func BenchmarkTraverseGoodStruct(b *testing.B) {
 for n := 0; n < b.N; n++ {
  traverseGoodStruct()
 }
}

func BenchmarkTraverseBadStruct(b *testing.B) {
 for n := 0; n < b.N; n++ {
  traverseBadStruct()
 }
}

GoodStructBadStruct進行基準測試的方法是循環遍歷數組,並將 struct 字段累加到變量中。

從結果中可以看出,遍歷GoodStruct確實比BadStruct花費時間更少。

對 struct 字段重排序可以優化應用程序的內存使用和速度。

想象一下,維護一個具有大量結構體的大型應用程序,改變將會更爲明顯。

結語

好了,全文到此爲止,我們以一個簡單的行動呼籲來結束:

一定要對 struct 結構字段進行重排序!


你好,我是俞凡,在 Motorola 做過研發,現在在 Mavenir 做技術工作,對通信、網絡、後端架構、雲原生、DevOps、CICD、區塊鏈、AI 等技術始終保持着濃厚的興趣,平時喜歡閱讀、思考,相信持續學習、終身成長,歡迎一起交流學習。爲了方便大家以後能第一時間看到文章,請朋友們關注公衆號 "DeepNoMind",並設個星標吧,如果能一鍵三連 (轉發、點贊、在看),則能給我帶來更多的支持和動力,激勵我持續寫下去,和大家共同成長進步!

參考資料

[1]

How to Speed Up Your Struct in Golang: https://betterprogramming.pub/how-to-speed-up-your-struct-in-golang-76b846209587

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/lyRahvkVr2rkwIcEN1pFng