Go Sync Pool


原文链接: Go Sync Pool

一个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{}类型的值放置于池中。
最简单的例子

// 一个[]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

上面代码的运行结果显示使用对象池很明显提升了性能

一个sync.Pool对象就是一组临时对象的集合。Pool是协程安全的。

Pool用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力。

如下是使用的两种方式:

一:

func main() {

   for index := 0; index < 100; index++ {
      go sss()
      //go ssse()
   }
   time.Sleep(2 * time.Second)
}
var sp = &sync.Pool{}
func sss() {
   sin := sp.Get()
   var buf *bytes.Buffer
   if sin != nil {
      buf = sin.(*bytes.Buffer)
   } else {
      buf = bytes.NewBuffer(make([]byte, 0, 65536))
   }

   buf.Write([]byte("hello world"))
   fmt.Println(buf.String())

   buf.Reset()
   sp.Put(buf)
}

二:

package collection

import (
   "bytes"
   "sync"
)

type BufferPool struct {
   sync.Pool
}

func NewBufferPool(bufferSize int) (bp *BufferPool) {
   return &BufferPool{
      sync.Pool{
         New: func() interface{} {
            return bytes.NewBuffer(make([]byte, 0, bufferSize))
         },
      },
   }
}

func (bp *BufferPool) Get() *bytes.Buffer {
   return bp.Pool.Get().(*bytes.Buffer)
}

func (bp *BufferPool) Put(b *bytes.Buffer) {
   b.Reset()
   bp.Pool.Put(b)
}



var buffers = collection.NewBufferPool(65536)

func main() {

   for index := 0; index < 100; index++ {
      go sss()
      //go ssse()
   }
   time.Sleep(2 * time.Second)
}

func ssse() {
   buf := buffers.Get()
   buf.Write([]byte("hello world"))
   fmt.Println(buf.String())

   buffers.Put(buf)
}

第二种采用了实现其 sync.Pool 的 new 接口,使用起来更加的方便快捷。

总结:sync.Pool的定位不是做类似连接池的东西,它的用途仅仅是增加对象重用的几率,减少gc的负担,从而减少内存开销。

`