sync.Pool 包寥寥不过300行代码,却可以为我们提供类似对象池的功能,减少了对象的重复创建于销毁,减少了性能损耗,增加内存复用,同时自带 mutex 锁可以保证 Put/Get 操作的并发安全特性,在一些对象需要重复创建销毁的场景中很是实用,今天来看看 sync.Pool 的基本原理。
sync.Pool 就在标准库中,注释开篇就是:
// A Pool is a set of temporary objects that may be individually saved and
// retrieved.
//
// Any item stored in the Pool may be removed automatically at any time without
// notification. If the Pool holds the only reference when this happens, the
// item might be deallocated.
//
// A Pool is safe for use by multiple goroutines simultaneously.
翻译过来就是:
1.对象池是提供一种存储、获取临时对象的集合
2.不要把对象池当做缓存来处理,因为任何存储的对象,在某个时刻都可能会被回收掉,而且没有任何通知的情况下
3.这个对象池的使用是并发安全的
继续往下看:
// Pool's purpose is to cache allocated but unused items for later reuse,
// relieving pressure on the garbage collector. That is, it makes it easy to
// build efficient, thread-safe free lists. However, it is not suitable for all
// free lists.
//
// An appropriate use of a Pool is to manage a group of temporary items
// silently shared among and potentially reused by concurrent independent
// clients of a package. Pool provides a way to amortize allocation overhead
// across many clients.
翻译过来:
1.对象池的目的是用来缓存那些已分配但是在后续的重复使用的对象,可以减轻GC压力
2.对象池一种合适的使用场景,是在多个客户端之间共享重用对象,得以分摊内存分配的开销
后面的注释也提到,其实在 fmt 包中也是有 Pool 使用的体现,内部维护了一个动态大小的临时输出 buffer 空间。
需要注意的点:
1.短生命周期的对象不太适合放对象池中
2.对象池不要复制
3.一般的使用场景,先声明 New(),然后再去使用 Get()/Put() 方法,可以 put 任何对象,但在 get 对象的时候,需要用到断言,即 Get().(Type)
4.对象池中的对象数量不能做任何假设,什么时候新建什么时候被GC,这些都是不确定的,对象池主要是能尽可能复用对象,减少GC
5.Pool本身的数据结构是并发安全,但是 Pool.New() 方法需要使用者注意场景使用,如并发下,则加上并发安全策略,如原子操作或者加互斥锁等
标签:Get,对象,sync,golang,并发,GC,Pool
From: https://www.cnblogs.com/davis12/p/18295610