在项目库中看到有用到sync.Pool字段,很好奇具体的作用,简单学习了一下,写个小博客总结一下。
sync.Pool 可以看作一个存放临时对象的池,使用到该对象时,可以从pool里拿,不需要时就归还到pool里。
为什么需要sync.Pool?直接声明Object不可以吗?Golang明明是有GC的语言。
但其实,如果可以复用对象,就能大大节省对象创建和回收的开销,从而达到优化内存使用的目的。对大对象,频繁使用的对象来说,该优化很有必要。
首先,sync.Pool对象池中的对象并非永久存放,任何物品都可能在任意时间被移除。如果只有对象池拥有某个对象的引用,该对象就会被释放内存。
其次,sync.Pool作为sync包下的一个模块,也拥有多线程安全的特性。Pool中的对象可以被多个独立并行的客户端取用。sync.Pool还拥有在多个客户端之间分摊内存分配开销的机制。
最后,sync.Pool拥有自动扩容缩容的功能。同一类的对象官方推荐使用单例pool,同时,pool在第一次使用后不允许被拷贝。
看源码
type Pool struct {
// ...
// 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() any
}
func (p *Pool) Get() any
func (p *Pool) Put(x any)
sync.Pool 的使用非常简单,在获取物品时,应调用Get()方法,在归还物品时,使用Put()方法。在使用Pool前,应定义New的方法。在调用Get()方法且池中尚无物品时,会优先调用New的函数生成物品并返回,否则,Get()就会返回nil。
以下是一个例子:
//声明
objectPool *sync.Pool
//定义New函数
objectPool = &sync.Pool{
New: func() interface{} {
return &Object{}
}
//使用物品
obj := objectPool.Get().(*Object)
//归还物品
objectPool.Put(obj)
关于sync.Pool机制更详细的说明可以看这篇博客