Go的sync.Pool

sync.Pool是来自Go 1.3版本加入的特性,可以被看做是存放可被重用的值的容器,这个容器具有以下特性:
1. 可自动伸缩
2. 高效
3. 并发安全

因此这个类设计的目的是用来保存和复用临时对象,以减少内存分配,降低CG压力,但是由于这个原因,所以它并不可靠,因此每次GC,都会首先清楚缓冲区,假如一个slice是存放在 Pool 中,而又没有其他地方引用,则会被当成垃圾清理掉,因此切勿用sync.Pool创建socket连接.

通过sync.Pool的源码,可以看出Pool创建的时候是不能指定大小的,所有sync.Pool的缓存对象数量是没有限制的,它只受限于内存大小.

通过Get方法获取到的值是任意的.如果一个临时对象池的Put方法未被调用过,且它的New字段也未曾被赋予一个非nil的函数值,那么它的Get方法返回的结果值就一定会是nil.

Get方法返回的不一定就是存在于池中的值.不过,如果这个结果值是池中的,那么在该方法返回它之前就一定会把它从池中删除掉.

一个例子:

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

编译时,禁用编译优化:go build -gcflags="-l -N".