日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Go編程庫Sync.Pool用法示例詳解_Golang

作者:小馬別過河 ? 更新時間: 2023-01-14 編程語言

場景

go 如果頻繁地創建、銷毀對象(比如 http 服務的 json 對象,日志內容等),會對 GC 造成壓力。比如下面的 Log 函數,在高并發情況下,需要頻繁地創建和銷毀 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 維護著一組對象池,需要時從對象池拿對象,不需要放回對象池就可以了。它有這些特點:

  • 忙時會自動擴容對象池,閑時會自動縮容;
  • 線程安全;
  • 對象池的對象,會未經通知地自動刪除;
  • 不能被 copy。

用法

創建

初始化時指定 New 方法。sync.Pool 會通過 New 方法創建對象池的對象。一般返回一個指針。

// 從對象池里取 buffer 時,如果池里沒 buffer了,則調用 New 創建一個新的。
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)

優化 Log 函數

Log 函數可以使用 sync.Pool 的優化,代碼如下:

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)
}

性能測試

我們對兩個函數進行性能測試

// 不使用 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,優化效果還是挺明顯的。

參考:

[1]. pkg.go.dev/sync#Pool

原文鏈接:https://juejin.cn/post/7166051649335590925

欄目分類
最近更新