Golang性能優(yōu)化的技巧分享
一.簡介
? 性能優(yōu)化的前提是滿足正確可靠、簡潔清晰等質(zhì)量因素。性能優(yōu)化是綜合評估,有時候時間效率和空間效率可能對立。針對 Go語言特性,下文介紹 Go 相關的性能優(yōu)化建議。
二.性能優(yōu)化建議
1.Benchmark
Benchmark能夠為Go語言提供支持基準性能測試,能夠提供實際的數(shù)據(jù)衡量。通過go test -bench=. -benchmen命令進行基準性能測試。
// from fib.go
func Fib(n int) int {
if n <2{
return n
}
return Fib(n-1) + Fib(n-2)
}
// from fib_test.go
func BenchmarkFib10(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++{
Fib(10)
}
}結(jié)果說明:

第四行第一個結(jié)果表示BenchmarkFib10是測試函數(shù)名8 表示GOMAXPROCS的值為8,第四行第二個結(jié)果表示一共執(zhí)行1855870次即b.N的值,第四行第三個結(jié)果表示每次執(zhí)行花費602.5ns,第四行第四個結(jié)果表示每次執(zhí)行申請多大的內(nèi)存,第四行第五個結(jié)果表示每次執(zhí)行申請的幾次內(nèi)存。
2.slice
? slice可以預分配內(nèi)存,使用make() 初始化切片時提供容量信息。
func NoPreAlloc( size int) {
data := make([]int, 0)
for k := 0; k < size; k++ {
data = append( data, k )
}
}
func PreAlloc(size int) {
data := make([]int, 0, size )
for k := 0; k < size; k++ {
data = append( data, k )
}
}實驗結(jié)果:

切片本質(zhì)是一個數(shù)組片段的描述包括數(shù)組指針,片段的長度,片段的容量(不改變內(nèi)存分配情況下的最大長度)。切片操作并不復制切片指向的元素,創(chuàng)建一個新的切片會復用原來切片的底層數(shù)組。
3.map
map預分配內(nèi)存
func NoPreAlloc(size int) {
data := make(map[int]int )
for i := 0; i < size; i++ {
data[i] = 1
}
}
func PreAlloc(size int) {
data := make(map[int]int, size)
for i := 0; i < size; i++{
data[i] = 1
}
}實驗結(jié)果:

不斷向 map 中添加元素的操作會觸發(fā) map 的擴容,提前分配好空間可以減少內(nèi)存拷貝和 Rehash 的消耗,根據(jù)實際需求提前預估好需要的空間。
4.字符串處理
使用strings.Builder
func ByteBuffer(n int, str string) string {
buf := new( bytes .Buffer)
for i := 0;i < n; i++ {
buf.writeString(str)
}
return buf.String()
}實驗結(jié)果:

使用 +字符串拼接性能最差,strings.Builder,bytes.Buffer 相近,strings.Buffer 更快。字符串在 Go語言中是不可變類型,占用內(nèi)存大小是固定的。使用 + 每次都會重新分配內(nèi)存。strings.Builder,bytes.Buffer 底層都是 []byte 數(shù)組。內(nèi)存擴容策略不需要每次拼接重新分配內(nèi)存。
5.空結(jié)構(gòu)體
空結(jié)構(gòu)體 struct{}實例不占據(jù)任何的內(nèi)存空間??勺鳛楦鞣N場景下的占位符使用,節(jié)省資源,空結(jié)構(gòu)體本身具備很強的語義,即這里不需要任何值,僅作為占位符。
func EmptyStructMap(n int) {
m := make(map[int]struct{})
for i := 0;i < n; i++ {
m[i] = struct{}{}
}
}
func BoolMap(n int) {
m := make(map[int]bool)
for i := 0;i < n; i++ {
m[i] = false
}
}實驗結(jié)果:

實現(xiàn) Set,可以考慮用 map 來代替。對于這個場景,只需要用到 map 的鍵,而不需要值。即使是將 map 的值設置為 bool 類型,也會多占據(jù) 1個字節(jié)空間。
6.atomic
使用atomic包
type atomicCounter struct {
i int32
}
func AtomicAddOne( c
*atomicCounter) {
atomic.AddInt32( &c.i, 1)
}
type mutexCounter struct {
i int32
m sync.Mutex
}
func MutexAddOne(c *mutexCounter) {
c.m.Lock()
c.i+
c.m.Unlock()
}實驗結(jié)果:

鎖的實現(xiàn)是通過操作系統(tǒng)來實現(xiàn),屬于系統(tǒng)調(diào)用。atomic 操作是通過硬件實現(xiàn),效率比鎖高。sync.Mutex 應該用來保護一段邏輯,不僅僅用于保護一個變量。對于非數(shù)值操作,可以使用 atomic.Value,能承載一個interface。
三.小結(jié)
避免常見的性能陷阱可以保證大部分程序的性能。普通應用代碼,不要一味地追求程序的性能。越高級的性能優(yōu)化手段越容易出現(xiàn)問題。在滿足正確可靠、簡潔清晰的質(zhì)量要求的前提下提高程序性能。
到此這篇關于Golang性能優(yōu)化的技巧分享的文章就介紹到這了,更多相關Go性能優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang中調(diào)用deepseekr1的教程詳解
這篇文章主要為大家詳細介紹了Golang中調(diào)用deepseekr1的相關教程,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以了解下2025-02-02
實現(xiàn)像php一樣方便的go ORM數(shù)據(jù)庫操作示例詳解
這篇文章主要為大家介紹了實現(xiàn)像php一樣方便的go ORM數(shù)據(jù)庫操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
Go語言并發(fā)之Sync包的6個關鍵概念總結(jié)
這篇文章主要為大家詳細介紹了Go語言并發(fā)中Sync包的6個關鍵概念,文中的示例代碼講解詳細,對我們深入學習Go語言有一定的幫助,需要的可以參考一下2023-05-05

