Go編程庫Sync.Pool用法示例詳解
場景
go 如果頻繁地創(chuàng)建、銷毀對象(比如 http 服務的 json 對象,日志內容等),會對 GC 造成壓力。比如下面的 Log
函數(shù),在高并發(fā)情況下,需要頻繁地創(chuàng)建和銷毀 buffer。
func Log(w io.Writer, key, val string) { b := new(bytes.Buffer) // 按一定的格式打印日志,這一段不是重點 b.WriteString(time.Now().UTC().Format(time.RFC3339)) b.WriteByte(' ') b.WriteString(key) b.WriteByte('=') b.WriteString(val) b.WriteByte('\n') w.Write(b.Bytes()) }
這時候可以考慮復用這些 buffer。我們可以維護一個 buffer 的對象池,需要的時候從對象池拿 buffer,用完放回對象池。這時候就推薦使用 sync.Pool 了。
sync.Pool 維護著一組對象池,需要時從對象池拿對象,不需要放回對象池就可以了。它有這些特點:
- 忙時會自動擴容對象池,閑時會自動縮容;
- 線程安全;
- 對象池的對象,會未經(jīng)通知地自動刪除;
- 不能被 copy。
用法
創(chuàng)建
初始化時指定 New 方法。sync.Pool 會通過 New 方法創(chuàng)建對象池的對象。一般返回一個指針。
// 從對象池里取 buffer 時,如果池里沒 buffer了,則調用 New 創(chuàng)建一個新的。 var bufPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, }
GET & PUT
通過 Get 獲取對象池的對象。當使用完畢,通過 Put 把對象返回對象池。
b := bufPool.Get().(*bytes.Buffer) // 從對象池拿 buffer 對象 // 操作對象,這個不重要 b.Reset() b.WriteString(time.Now().UTC().Format(time.RFC3339)) // 操作完放回對象池 bufPool.Put(b)
優(yōu)化 Log 函數(shù)
Log 函數(shù)可以使用 sync.Pool 的優(yōu)化,代碼如下:
var bufPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } func LogWithPool(w io.Writer, key, val string) { // 從對象池拿 buffer b := bufPool.Get().(*bytes.Buffer) b.Reset() // 按一定的格式打印日志,這一段不是重點 b.WriteString(time.Now().UTC().Format(time.RFC3339)) b.WriteByte(' ') b.WriteString(key) b.WriteByte('=') b.WriteString(val) b.WriteByte('\n') w.Write(b.Bytes()) // 放回對象池 bufPool.Put(b) }
性能測試
我們對兩個函數(shù)進行性能測試
// 不使用 sync.Pool func BenchmarkLog(b *testing.B) { writer := os.NewFile(0, os.DevNull) for n := 0; n < b.N; n++ { Log(writer, "path", "/search?a=flowers") } } // 使用 sync.Pool 復用 func BenchmarkLogWithPool(b *testing.B) { writer := os.NewFile(0, os.DevNull) for n := 0; n < b.N; n++ { LogWithPool(writer, "path", "/search?a=flowers") } }
結果:
> go test -bench . -benchmem
goos: darwin
goarch: amd64
pkg: example/pool
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkLog-8 1849365 635.0 ns/op 112 B/op 2 allocs/op
BenchmarkLogWithPool-8 1993304 614.4 ns/op 48 B/op 1 allocs/op
PASS
ok example/pool 4.333s
相比之下,使用 Sync.Pool 和不使用的時候,內存的使用比為 48:112,優(yōu)化效果還是挺明顯的。
參考:
[1]. pkg.go.dev/sync#Pool
以上就是Go編程庫Sync.Pool用法示例詳解的詳細內容,更多關于Go庫Sync.Pool的資料請關注腳本之家其它相關文章!
相關文章
解決Go?Json?Unmarshal反序列化丟失數(shù)字精度問題
業(yè)務會使用?id生成器?產(chǎn)生的?分布式唯一ID,長度比較長,所以代碼反序列化時,會出現(xiàn)精度丟失問題,那如何解決呢,下面小編就來和大家詳細講講2023-08-08通過函數(shù)如何將golang?float64?保留2位小數(shù)(方法匯總)
這篇文章主要介紹了通過函數(shù)將golang?float64保留2位小數(shù),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08Golang實現(xiàn)優(yōu)雅的將struct轉換為map
在項目實踐中,有時候我們需要將struct結構體轉為map映射表,然后基于map做數(shù)據(jù)裁剪或操作。那么下面我來介紹下常用的兩種轉換方式,希望對大家有所幫助2023-01-01