sync.Pool 除了最常见的池化提升性能的思路,最重要的是减少 GC 。
常用于一些对象实例创建昂贵的场景。注意,Pool 是 Goroutine 并发安全的。
一、sync.Pool 适应场景
sync.Pool 本质用途是增加临时对象的重用率,减少 GC 负担;
sync.Pool 中保存的元素有如下特征:
- Pool 池里的元素随时可能释放掉,释放策略完全由 runtime 内部管理;
- Get 获取到的元素对象可能是刚创建的,也可能是之前创建好 cache 的,使用者无法区分;
- Pool 池里面的元素个数你无法知道;
所以,只有的你的场景满足以上的假定,才能正确的使用 Pool 。
划重点:临时对象。像 socket 这种带状态的、长期有效的资源是不适合 Pool 的。
二、sync.Pool 使用方法
1.初始化 Pool 实例 New
创建一个 Pool 实例,关键一点是配置 New 方法,声明 Pool 元素创建的方法。源码1.15版本的 Pool.go 声明 Pool结构如下:
// A Pool must not be copied after first use.
type Pool struct {
noCopy noCopy
local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
localSize uintptr // size of the local array
victim unsafe.Pointer // local from previous cycle
victimSize uintptr // size of victims array
// New optionally specifies a function to generate
// a value when Get would otherwise return nil.
// It may not be changed concurrently with calls to Get.
New func() interface{} // New是一个方法、返回值为 接口
}
如何给此方法赋值呢?
bufPool := &sync.Pool {
New: func() interface{} {
//函数体内容
return struct {}{}
}
}
2.申请对象 Get
Get 方法会返回 Pool 已经存在的对象;如果没有就使用New方法创建.
3.释放对象 Put
对象或资源不用时,调用 Put 方法把对象或资源放回池子,池子里面的对象啥时候真正释放是由 go_runtime进行回收,是不受外部控制的。
三、sync.Pool 实例
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
var createNum int32
func createBuffer() interface{} {
atomic.AddInt32(&createNum, 1)
buffer := make([]byte, 1024)
return buffer
}
func main() {
bufferPool := &sync.Pool{New: createBuffer,}
workerPool := 1024 * 1024
var wg sync.WaitGroup
wg.Add(workerPool)
for i := 0; i < workerPool; i++ {
go func(){
defer wg.Done()
buffer := bufferPool.Get()
_ = buffer.([]byte)
defer bufferPool.Put(buffer)
//buffer := createBuffer()
//_ = buffer.([]byte)
}()
}
wg.Wait()
fmt.Printf(" %d buffer objects were create.\n",createNum)
time.Sleep(5 * time.Second)
}
运行效果
robot@ubuntu:~/gomod/src/sync$ go run syncPool.go
4 buffer objects were create.
robot@ubuntu:~/gomod/src/sync$ go run syncPool.go
4 buffer objects were create.
使用 pool 申请 1024 *1024 个 1k buffer 缓存,而实际调用 createBuffer 创建次数只有4次;
创建次数与机器的运行环境有关,未必相同。