go的臨時對象池--sync.Pool

做者:bigtom
連接:https://www.jianshu.com/p/2bd41a8f2254
來源:簡書
 
一個sync.Pool對象就是一組臨時對象的集合。Pool是協程安全的。
Pool用於存儲那些被分配了可是沒有被使用,而將來可能會使用的值,以減少垃圾回收的壓力。一個比較好的例子是fmt包,fmt包老是須要使用一些[]byte之類的對象,golang創建了一個臨時對象池,存放着這些對象,若是須要使用一個[]byte,就去Pool裏面拿,若是拿不到就分配一份。
這比起不停生成新的[]byte,用完了再等待gc回收來要高效得多。
type buffer []byte
// pp是用於存儲printer狀態的一個結構體
type pp struct {
    buf buffer
    arg interface{}
    value reflect.Value
    fmt fmt
    reordered bool
    goodArgNum bool
    panicking bool
    erroring bool
}
//一個pp的對象池
var ppFree = sync.Pool{
    New: func() interface{} { return new(pp) },
}
// 分配一個新的pp或者拿一個緩存的。
func newPrinter() *pp {
    p := ppFree.Get().(*pp)
    p.panicking = false
    p.erroring = false
    p.fmt.init(&p.buf)
    return p
}

sync.Pool有兩個公開的方法。一個是Get,另外一個是Put。前者的功能是從池中獲取一個interface{}類型的值,然後者的做用則是把一個interface{}類型的值放置於池中。golang

最簡單的例子

// 一個[]byte的對象池,每一個對象爲一個[]byte
var bytePool = sync.Pool{
  New: func() interface{} {
    b := make([]byte, 1024)
    return &b
  },
}

func main() {
  a := time.Now().Unix()
  // 不使用對象池
  for i := 0; i < 1000000000; i++{
    obj := make([]byte,1024)
    _ = obj
  }
  b := time.Now().Unix()
  // 使用對象池
  for i := 0; i < 1000000000; i++{
    obj := bytePool.Get().(*[]byte)
    _ = obj
    bytePool.Put(obj)
  }
  c := time.Now().Unix()
  fmt.Println("without pool ", b - a, "s")
  fmt.Println("with    pool ", c - b, "s")
}

// without pool  34 s
// with    pool  24 s

  

上面代碼的運行結果顯示使用對象池很明顯提高了性能  緩存

相關文章
相關標籤/搜索