1.介绍
1.1sync.Pool是什么
sync.pool
是Go1.3
发布的一个特性,它是一个临时对象存储池,程序员使用时不能对Pool中的元素个数做假定
1.2为什么使用sync.Pool
1.保存和复用临时对象
2.减少内存分配
3.降低GC压力
1.3sync.Pool方法有哪些
//初始化Pool实例
New func() interface{}
//申请对象
//Get方法会返回Pool中已经存在的对象,如果不存在,就调用New初始化
func (p *Pool) Get() interface{}
//释放对象
//使用完对象后,要放回赤字中。注意:池子中的对象什么时候真正释放是不受外界控制的。
func (p *Pool) Put(x interface{})
1.4思考?
1.为什么使用Pool,而不是在运行的时候直接实例话对象呢?
2.sync.Pool是并发安全的吗?
3.为什么sync.Pool不适合用于像socket长链接活数据库连接池?
2.案例
package main
import (
"fmt"
"sync"
"sync/atomic"
)
// 用来统计实例真正创建的次数
var numCalcsCreated int32
// 创建实例的函数
func createBuffer() interface{} {
// 这里要注意下,非常重要的一点。这里必须使用原子加,不然有并发问题;
atomic.AddInt32(&numCalcsCreated, 1)
buffer := make([]int, 0, 100)
return &buffer
}
func main() {
// 创建实例
bufferPool := &sync.Pool{
New: createBuffer,
}
// 多 goroutine 并发测试
numWorkers := 30
var wg sync.WaitGroup
wg.Add(numWorkers)
for i := 0; i < numWorkers; i++ {
routineNum := i
go func() {
defer wg.Done()
// 申请一个 buffer 实例
buffer := bufferPool.Get()
li := buffer.(*[]int)
*li = append(*li, routineNum, routineNum+1, routineNum+2)
fmt.Println(li)
// 释放一个 buffer 实例
defer func() {
//使用完了恢复原样
*li = []int{}
bufferPool.Put(buffer)
}()
}()
}
wg.Wait()
fmt.Printf("%d buffer objects were created.\n", numCalcsCreated)
}
上面例子我们看到,一次创建了9次buffer,一次创建了11次buffer。
2.1减小对象的创建
如果我们不使用Pool来申请实例,而是直接申请,对象的创建数量和并发Worker数量相同,==30
所以使用Pool能够减少对象的创建,减少内存分配,今儿也减小GC对临时对象的回收次数。
2.2Pool是并发安全的
sync.Pool只是本身的Pool数据结构是并发安全的,并不是说Pool.New函数是线程安全的。
所在在New函数中,我们使用了 atomic.AddInt32(&numCalcsCreated, 1) 来避免并发问题。
2.3为什么sync.Pool不适合用于socket或数据库连接池呢?
因为,我们不能对 sync.Pool 中保存的元素做任何假设,以下事情是都可以发生的:
- Pool 池里的元素随时可能释放掉,释放策略完全由 runtime 内部管理;
- Get 获取到的元素对象可能是刚创建的,也可能是之前创建好 cache 住的。使用者无法区分;
- Pool 池里面的元素个数你无法知道;
sync.Pool 本质用途是增加临时对象的重用率,减少 GC 负担。划重点:临时对象。所以说,像 socket 这种带状态的,长期有效的资源是不适合 Pool 的。
总结:
- sync.Pool 本质用途是增加临时对象的重用率,减少 GC 负担;
- 不能对 Pool.Get 出来的对象做预判,有可能是新的(新分配的),有可能是旧的(之前人用过,然后 Put 进去的);
- 不能对 Pool 池里的元素个数做假定,你不能够;
- sync.Pool 本身的 Get, Put 调用是并发安全的,
sync.New
指向的初始化函数会并发调用,里面安不安全只有自己知道; - 当用完一个从 Pool 取出的实例时候,一定要记得调用 Put,否则 Pool 无法复用这个实例,通常这个用 defer 完成;