掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流
如果你有Golang開發(fā)經(jīng)驗,一定定義過struct類型。

我們提供的服務有:成都網(wǎng)站設計、成都做網(wǎng)站、外貿網(wǎng)站建設、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、元謀ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的元謀網(wǎng)站制作公司
但可能你不知道,通過簡單的重新排序struct字段,可以極大提高Go程序的速度和內存使用效率!
是不是難以置信?我們一起來看一下吧!
type BadStruct struct {
age uint8
passportNum uint64
siblings uint16
}
type GoodStruct struct {
age uint8
siblings uint16
passportNum uint64
}在上面的代碼片段中,我們創(chuàng)建了兩個具有相同字段的結構體。然后編寫一個簡單程序分別輸出其內存使用情況。
// Output
Bad struct is 24 bytes long
Good struct is 16 bytes long如你所見,它們在內存使用方面并不一樣。
是什么原因導致兩個完全相似的struct消耗的內存不同?
答案在于數(shù)據(jù)在計算機內存中的排列方式。
簡而言之,數(shù)據(jù)結構對齊。
CPU以字(word)為單位讀取數(shù)據(jù),而不是字節(jié)(byte)。
64位系統(tǒng)中,一個word是8個字節(jié),而32位系統(tǒng)中,一個word是4個字節(jié)。
簡而言之,CPU以其字長的倍數(shù)讀取內存地址。
想象一下,在64位系統(tǒng)中,為了獲取變量passportNum,CPU需要兩個周期來訪問數(shù)據(jù)。
第一個周期將獲取內存的0到7字節(jié),下一個周期獲取其余內存字節(jié)。
把它想象成一個筆記本,每頁只能存儲一個字大小的數(shù)據(jù)(在本例中為8字節(jié))。如果passportNum分散在兩個頁,則需要兩次讀取才能檢索到完整的數(shù)據(jù)。
非常低效。
因此需要數(shù)據(jù)結構對齊,讓計算機將數(shù)據(jù)存儲在等于數(shù)據(jù)大小倍數(shù)的地址上。
4字節(jié)數(shù)據(jù)只能從內存地址0或4開始
例如,2字節(jié)數(shù)據(jù)可以存儲在內存0、2或4中,而4字節(jié)數(shù)據(jù)可以存儲在內存0、4或8中。
通過簡單的對齊數(shù)據(jù),計算機確??梢栽谝粋€CPU周期內檢索到變量passportNum。
填充是實現(xiàn)數(shù)據(jù)對齊的關鍵。
計算機通過在數(shù)據(jù)結構之間填充額外的字節(jié),從而對齊字段。
這就是額外內存的來源!
我們來回顧一下BadStruct和GoodStruct。
GoodStruct消耗更少的內存,僅僅因為與BadStruct相比,其struct字段順序更合理。
由于填充,兩個13字節(jié)的數(shù)據(jù)結構分別變成了16字節(jié)和24字節(jié)。
因此,可以僅僅通過對struct字段重新排序來節(jié)省額外的內存!
問題來了,你為什么要關心這個?
兩個方面,速度和內存使用。
我們做一個簡單的基準測試來證明!
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進行基準測試的方法是循環(huán)遍歷數(shù)組,并將struct字段累加到變量中。
從結果中可以看出,遍歷GoodStruct確實比BadStruct花費時間更少。
對struct字段重排序可以優(yōu)化應用程序的內存使用和速度。
想象一下,維護一個具有大量結構體的大型應用程序,改變將會更為明顯。
好了,全文到此為止,我們以一個簡單的行動呼吁來結束:一定要對struct結構字段進行重排序!

我們在微信上24小時期待你的聲音
解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網(wǎng)交流