# (sync.Pool)[https://github.com/golang/go/blob/go1.22.11/src/sync/pool.go]
# 数据结构
type Pool struct { | |
noCopy noCopy | |
local unsafe.Pointer // 指向每个 P(处理器)的本地对象池,实际类型为 [P] poolLocal | |
localSize uintptr //local 数组的大小(即 P 的数量) | |
victim unsafe.Pointer // 指向上一个 GC 周期的本地对象池,用于 GC 回收 | |
victimSize uintptr //victim 数组的大小 | |
// New 可选函数,用于在 Get 返回 nil 时生成新对象 | |
// 不能与 Get 并发修改 | |
New func() any | |
} | |
//poolLocal 是每个 P 的本地对象池 | |
type poolLocal struct { | |
poolLocalInternal | |
//pad 字段用于填充内存,防止 false sharing | |
// 在主流平台上,使结构体大小为 128 字节的整数倍 | |
// 这样可以确保不同 P 的 poolLocal 位于不同的缓存行,避免缓存失效 | |
pad [128 - unsafe.Sizeof(poolLocalInternal{})%128]byte | |
} | |
//poolLocalInternal 每个 P(处理器)专属的对象池内部结构 | |
type poolLocalInternal struct { | |
private any //private 只能被对应的 P 使用,用于快速访问 | |
shared poolChain //shared 是一个共享队列,本地 P 可以在队首进行 push/pop 操作,其他 P 可以从队尾 pop | |
} |
//poolChain 实现了一个双向链表结构的对象池队列 | |
type poolChain struct { | |
//head 指向用于 push 操作的 poolDequeue | |
// 只被生产者访问,因此不需要同步 | |
head *poolChainElt | |
//tail 指向用于 popTail 操作的 poolDequeue | |
// 被消费者访问,因此读写必须是原子操作 | |
tail *poolChainElt | |
} | |
//poolChainElt 是 poolChain 中的链表节点 | |
type poolChainElt struct { | |
poolDequeue // 嵌入 poolDequeue 实现底层的队列功能 | |
//next 和 prev 指向 poolChain 中相邻的节点 | |
// | |
//next 由生产者原子写入,由消费者原子读取 | |
// 只能从 nil 变为非 nil | |
// | |
//prev 由消费者原子写入,由生产者原子读取 | |
// 只能从非 nil 变为 nil | |
next, prev *poolChainElt | |
} | |
//poolDequeue 实现了一个无锁循环队列 | |
type poolDequeue struct { | |
headTail atomic.Uint64 // 使用一个 64 位整数同时存储队列的头尾指针 | |
// 高 32 位存储 head,低 32 位存储 tail | |
vals []eface // 存储对象的底层数组,使用 eface 接口类型表示任意对象 | |
} | |
//eface 表示一个空接口,用于存储任意类型的对象 | |
type eface struct { | |
typ unsafe.Pointer // 指向类型信息的指针 | |
val unsafe.Pointer // 指向实际数据的指针 | |
} |
# Get 操作
func (p *Pool) Get() any { | |
// | |
l, pid := p.pin() | |
x := l.private | |
l.private = nil | |
if x == nil { | |
// Try to pop the head of the local shard. We prefer | |
// the head over the tail for temporal locality of | |
// reuse. | |
x, _ = l.shared.popHead() | |
if x == nil { | |
x = p.getSlow(pid) | |
} | |
} | |
runtime_procUnpin() | |
if race.Enabled { | |
race.Enable() | |
if x != nil { | |
race.Acquire(poolRaceAddr(x)) | |
} | |
} | |
if x == nil && p.New != nil { | |
x = p.New() | |
} | |
return x | |
} |
# Put 操作
func (p *Pool) Put(x any) { | |
if x == nil { | |
return | |
} | |
if race.Enabled { | |
if runtime_randn(4) == 0 { | |
// Randomly drop x on floor. | |
return | |
} | |
race.ReleaseMerge(poolRaceAddr(x)) | |
race.Disable() | |
} | |
l, _ := p.pin() | |
if l.private == nil { | |
l.private = x | |
} else { | |
l.shared.pushHead(x) | |
} | |
runtime_procUnpin() | |
if race.Enabled { | |
race.Enable() | |
} | |
} |