GoLang之使用sync.pool
1.sync.Pool结构体
1.1sync.Pool结构体
Pool是一个可以分别存取的临时对象的集合。
Pool中保存的任何item都可能随时不做通告的释放掉。如果Pool持有该对象的唯一引用,这个item就可能被回收。
Pool可以安全的被多个线程同时使用。
Pool的目的是缓存申请但未使用的item用于之后的重用,以减轻GC的压力。也就是说,让创建高效而线程安全的空闲列表更容易。但Pool并不适用于所有空闲列表。
Pool的合理用法是用于管理一组静静的被多个独立并发线程共享并可能重用的临时item。Pool提供了让多个线程分摊内存申请消耗的方法。
Pool的一个好例子在fmt包里。该Pool维护一个动态大小的临时输出缓存仓库。该仓库会在过载(许多线程活跃的打印时)增大,在沉寂时缩小。
另一方面,管理着短寿命对象的空闲列表不适合使用Pool,因为这种情况下内存申请消耗不能很好的分配。这时应该由这些对象自己实现空闲列表。
type Pool struct {
// 可选参数New指定一个函数在Get方法可能返回nil时来生成一个值
// 该参数不能在调用Get方法时被修改
New func() interface{}
// 包含隐藏或非导出字段
}
//如下源码为Go Windos SDK v1.18
// 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.
//
// 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.
//
// An example of good use of a Pool is in the fmt package, which maintains a
// dynamically-sized store of temporary output buffers. The store scales under
// load (when many goroutines are actively printing) and shrinks when
// quiescent.
//
// On the other hand, a free list maintained as part of a short-lived object is
// not a suitable use for a Pool, since the overhead does not amortize well in
// that scenario. It is more efficient to have such objects implement their own
// free list.
//
// 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() any
}
1.2Put方法
Put方法将x放入池中。
//如下源码为Go Windos SDK v1.18
func (p *Pool) Put(x interface{})
//如下源码为Go Windos SDK v1.18
// Put adds x to the pool.
func (p *Pool) Put(x any) {}
1.3Get方法
Get方法从池中选择任意一个item,删除其在池中的引用计数,并提供给调用者。Get方法也可能选择无视内存池,将其当作空的。调用者不应认为Get的返回这和传递给Put的值之间有任何关系。
假使Get方法没有取得item:如p.New非nil,Get返回调用p.New的结果;否则返回nil。
func (p *Pool) Get() interface{}
//如下源码为Go Windos SDK v1.18
// Get selects an arbitrary item from the Pool, removes it from the
// Pool, and returns it to the caller.
// Get may choose to ignore the pool and treat it as empty.
// Callers should not assume any relation between values passed to Put and
// the values returned by Get.
//
// If Get would otherwise return nil and p.New is non-nil, Get returns
// the result of calling p.New.
func (p *Pool) Get() any {}
2.使用实例
2.1设置new字段
package main
import (
"fmt"
"sync"
)
func main() {
// 初始化一个pool
pool := &sync.Pool{
// 默认的返回值设置,不写这个参数,默认是nil
New: func() interface{} {
return 0
},
}
// 看一下初始的值,这里是返回0,如果不设置New函数,默认返回nil
init := pool.Get()
fmt.Println(init)//0
// 设置一个参数1
pool.Put(1)
// 获取查看结果
num := pool.Get()
fmt.Println(num)//1
// 再次获取,会发现,已经是空的了,只能返回默认的值。
num = pool.Get()
fmt.Println(num)//1
}
2.1不设置new字段
package main
import (
"fmt"
"sync"
)
func main() {
pool := &sync.Pool{}
init := pool.Get()
fmt.Println(init) //<nil>
pool.Put(1)
num := pool.Get()
fmt.Println(num) //1
num = pool.Get()
fmt.Println(num) //<nil>
}