sync.Pool对象池是Golang提供的对象重用机制,可以将它看作存放可重用对象值的容器,一般用于存放已经分配但暂时不用的对象,当需要的时候可以直接从pool中取。sync.Pool是可伸缩、并发安全的,它的大小受限于内存大小。
sync.Pool对象获取
sync.Pool获取对象的过程(Get):
- 尝试从私有对象获取
- 若私有对象不存在,从当前Processor的共享池获取
- 若依然为空,则尝试从其它Processor的共享池获取
- 若以上所有都是空的,最后从用户指定的New函数产生一个新的对象返回
私有对象是协程安全的,而共享池是非协程安全的。
sync.Pool对象放回
sync.Pool放入对象的过程(Put):
- 如果私有对象不存在,则保存为私有对象
- 若私有对象存在,则放入当前Processor的共享池中
sync.Pool对象的生命周期
- GC会清除sync.Pool缓存的对象
- 对象缓存有效期为下一次GC之前
示例
sync.Pool公开的方法有:New、Get、Put。先简单看一下它的用法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pool := sync.Pool{
New: func() interface{} {
return "test"
}
}
s := pool.Get()
fmt.Println(s)
pool.Put("helo")
s = pool.Get()
fmt.Println(s)
//Output:
// test
// hello
如果手动调用下GC:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pool := sync.Pool{
New: func() interface{} {
return "test"
}
}
s := pool.Get()
fmt.Println(s)
pool.Put("helo")
runtime.GC()
s = pool.Get()
fmt.Println(s)
//Output:
// test
// test
可以看到再次Get的时候已经不是上次Put进去的内容了,因为它可能已经被GC回收了,这时就会通过New函数来自动创建,如果没有注册New函数就会返回nil。
sync.Pool适合存储一些在多个goroutine间共享的临时对象,通过复用对象、减少GC提高性能。当使用共享池中的对象时,为了协程安全,会有锁的开销。
sync.Pool的生命周期受到GC影响,存放在sync.Pool中的值可能在任何时候被GC删除,它可以高负载下可以动态扩容,不活跃的时候对象池会自动收缩。