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
分散在兩個頁,則需要兩次讀取才能檢索到完整的數據。
非常低效。
因此需要數據結構對齊,讓計算機將數據存儲在等於數據大小倍數的地址上。
例如,2 字節數據可以存儲在內存 0、2 或 4 中,而 4 字節數據可以存儲在內存 0、4 或 8 中。
通過簡單的對齊數據,計算機確保可以在一個 CPU 週期內檢索到變量passportNum
。
數據結構填充
填充是實現數據對齊的關鍵。
計算機通過在數據結構之間填充額外的字節,從而對齊字段。
這就是額外內存的來源!
我們來回顧一下BadStruct
和GoodStruct
。
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()
}
}
對GoodStruct
和BadStruct
進行基準測試的方法是循環遍歷數組,並將 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