Pool
- 一个Pool是一群对象的集合,集合可能是单独存储
- Pool中存储的对象可以自动在池中移除而不用通知,当只有Pool持有对象的引用时,对象有可能会释放内存
- Pool是线程安全的
- Pool的创建用意是缓存已经分配内存且已经用完的对象,方便后续复用的时候不必申请内存,同时减轻gc的压力
- Pool适用于管理一组对象,可以被多个独立的客户端复用,从而避免每个客户端都要申请内存。
- 如果对象存在的声明周期很短,则不适合用Pool来管理
Pool结构体
|
|
- poolLocal是每个调度器P存储对象的结构体
- pad防止伪共享
- private为每个调度器的私有空间
- shared空间当前调度器可以pushHead和popTail,所有调度器都可以popTail
|
|
- poolChain为动态版的poolDequeue
|
|
Pool结构体的方法
- Put方法将对象添加到Pool中
- pin函数将当前goroutine绑定到指定的调度器P上,同时禁止抢占,返回poolLocal对象和绑定的Pid
- 从Pool的local中获取调度器P的poolLocal,没有需要新建123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869func (p *Pool) Put(x interface{}) {if x == nil { // 放入的对象为空,直接返回return}if race.Enabled { // 关闭竞争检测if fastrand()%4 == 0 {// Randomly drop x on floor.return}race.ReleaseMerge(poolRaceAddr(x))race.Disable() // 关闭操作}l, _ := p.pin()// 私有空间为空,则将x放置到私有空间if l.private == nil {l.private = xx = nil}// 私有空间已满,则将x放到公有空间中if x != nil {l.shared.pushHead(x)}runtime_procUnpin()if race.Enabled {race.Enable()}}func (p *Pool) pin() (*poolLocal, int) {pid := runtime_procPin() // 关闭抢占,这个goroutine工作完才释放时间片s := atomic.LoadUintptr(&p.localSize) // load-acquirel := p.local // load-consumeif uintptr(pid) < s { // 如果p.local的长度大于pid,则直接取数据即可return indexLocal(l, pid), pid}// pinSlow函数来完成p.local的新增return p.pinSlow()}func indexLocal(l unsafe.Pointer, i int) *poolLocal {lp := unsafe.Pointer(uintptr(l) + uintptr(i)*unsafe.Sizeof(poolLocal{}))return (*poolLocal)(lp)}func (p *Pool) pinSlow() (*poolLocal, int) {// 尝试重新将goroutine绑定到其他的goroutine,查看是否有poolLocal使用runtime_procUnpin()allPoolsMu.Lock()defer allPoolsMu.Unlock()pid := runtime_procPin()// poolCleanup won't be called while we are pinned.s := p.localSizel := p.local// 新绑定的P有poolLocal空间,则直接获取返回if uintptr(pid) < s {return indexLocal(l, pid), pid}// Pool为空,则将pool添加到allPools中if p.local == nil {allPools = append(allPools, p)}// 创建一个cpu数量大小的[]poolLocal并返回size := runtime.GOMAXPROCS(0)local := make([]poolLocal, size)atomic.StorePointer(&p.local, unsafe.Pointer(&local[0])) // store-releaseatomic.StoreUintptr(&p.localSize, uintptr(size)) // store-releasereturn &local[pid], pid}
Get方法
|
|