sync.Pool
目录
sync.Pool
1. 概述
sync.Pool是Go语言标准库中的一个类型,用于管理一组可重用的对象。它的主要目的是减少内存分配和垃圾回收的开销,提高程序的性能。
sync.Pool的工作原理是:当需要创建一个新的对象时,Pool会检查是否有可用的对象。如果有,Pool会返回一个可用的对象,而不是创建一个新的对象。这样可以避免频繁地进行内存分配和垃圾回收。
复用临时对象,减少频繁的内存分配和垃圾回收,提高程序的性能。
2. 基本使用
sync.Pool的使用方法如下:
package main
import (
"fmt"
"sync"
)
type MyStruct struct {
Name string // 结构体的字段
}
var pool = sync.Pool{
New: func() interface{} {
// 创建一个新的对象
return &MyStruct{}
},
}
func main() {
// 首次获取对象
obj := pool.Get().(*MyStruct)
fmt.Println("首次对象", obj.Name)
// 设置对象的字段
obj.Name = "Hello, World!"
// 将对象放回池中
pool.Put(obj)
// pool中存在对象
obj2 := pool.Get().(*MyStruct)
fmt.Println("pool中存在对象", obj2.Name)
// 再次获取对象
obj3 := pool.Get().(*MyStruct)
fmt.Println("再次获取对象", obj3.Name)
}
输出结果:
首次对象
pool中存在对象 Hello, World!
再次获取对象
3. 使用案例
gin 框架
gin 框架会给每个请求分配一个 Context 用以进行追踪,这就是典型的 sync.pool 使用场景:
func New() *Engine {
engine := &Engine{
}
engine.pool.New = func() interface{} {
return engine.allocateContext()
}
return engine
}
func (engine *Engine) allocateContext() *Context {
return &Context{engine: engine}
}
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset()
engine.handleHTTPRequest(c)
engine.pool.Put(c)
}
从 pool 中获取 Context 对象,用完后又还回去,注意 还回去之前这里也调用了 reset() 方法进行字段清空。
注意事项
- 设置 New 方法
- 使用时直接 Get
- 使用完成后先进行字段清空,然后在 Put 回去。
4. 原理解析
type Pool struct {
noCopy noCopy
local unsafe.Pointer // 每个P对应的本地固定大小池,实际类型是 [P]poolLocal
localSize uintptr // 本地数组的大小
victim unsafe.Pointer // 前一个生命周期的本地池
victimSize uintptr // 前一个生命周期池的大小
// New 可选地指定一个生成函数
// 当Get方法无法找到可用对象时,将通过这个函数创建新对象
// 注意:该字段不可与Get方法的调用并发修改
New func() any
}
字段详解:
- noCopy对象,实现了sync.Locker接口,使得内嵌了 noCopy 的对象在进行 go vet 静态检查的时候,可以检查出是否被复制。
- local 字段存储指向 [P]poolLocal 数组(严格来说,它是一个切片)的指针。localSize 则表示 local 数组的大小。
- 访问时,根据 P 的 id 去访问对应下标的 local[pid]
- 通过这样的设计,多个 goroutine 使用同一个 Pool 时,减少了竞争,提升了性能。有点类似于降低锁粒度,分段锁的思想。
- victim 和 victimSize 则会在在一轮 GC 到来时,分别“接管” local 和 localSize。
- victim cache 是一种提高缓存性能的硬件技术;
- victim 的机制用于减少 GC 后冷启动导致的性能抖动,让分配对象更平滑;
- sync.Pool 引入的意图在于降低 GC 压力的同时提高命中率。
- New就是我们指定的新建对象的方法。
Victim Cache 是一种提高缓存性能的硬件技术,主要用于提升缓存命令率。 所谓受害者缓存(Victim Cache),是一个与直接匹配或低相联缓存并用的、容量很小的全相联缓存。当一个数据块被逐出缓存时,并不直接丢弃,而是暂先进入受害者缓存。如果受害者缓存已满,就替换掉其中一项。当进行缓存标签匹配时,在与索引指向标签匹配的同时,并行查看受害者缓存,如果在受害者缓存发现匹配,就将其此数据块与缓存中的不匹配数据块做交换,同时返回给处理器。