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的负担,从而减少内存开销。