你们好,我是 frank。
欢迎你们点击上方蓝色文字「Golang 语言开发栈」关注公众号。
01golang
介绍编程
sync.Poolsync.Poolsync.Poolsync.Poolsync.Poolsync.Pool
sync.Poolsync.Pool
sync.Pool
sync.Pool
02并发
使用方式app
sync.Poll
- func (p *Pool) Put(x interface{})
- func (p *Pool) Get() interface{}
Put()interface{}Get()interface{}
Get()Get()Put()Get()
Get()p.NewGet()p.Newsync.PoolNewfunc() interface{}Get()
sync.PoolNewGet()
sync.Pool
示例代码:
`func main () {` `pool := &sync.Pool{` `New: func() interface{} {` `fmt.Println("New 一个新对象")` `return 0` `},` `}` `// 取,临时对象池中没有数据,会调用 New,New 建立一个新对象直接返回,不会存储在临时对象池中` `val := pool.Get().(int)` `fmt.Println(val)` `// 存` `pool.Put(10)` `// 手动调用 GC(),用于验证 GC 以后,临时对象池中的对象会被清空。` `runtime.GC()` `// 取` `val2 := pool.Get().(int)` `fmt.Println(val2)` `}`
03
实现原理
在 Go1.13 以前,临时对象池的数据结构中有一个本地池列表,在每一个本地池中包含三个字段,分别是存储私有临时对象的字段 private、共享临时对象列表的字段 shared 和 sync.Mutex 类型的嵌入字段。
sync.Pool
sync.Pool
`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() interface{}` `}`
Get()Get()
sync.Pool
`func poolCleanup() {` `// This function is called with the world stopped, at the beginning of a garbage collection.` `// It must not allocate and probably should not call any runtime functions.` `// Because the world is stopped, no pool user can be in a` `// pinned section (in effect, this has all Ps pinned).` `// Drop victim caches from all pools.` `for _, p := range oldPools {` `p.victim = nil` `p.victimSize = 0` `}` `// Move primary cache to victim cache.` `for _, p := range allPools {` `p.victim = p.local` `p.victimSize = p.localSize` `p.local = nil` `p.localSize = 0` `}` `// The pools with non-empty primary caches now have non-empty` `// victim caches and no pools have primary caches.` `oldPools, allPools = allPools, nil` `}`
Put()Get()
`// Local per-P Pool appendix.` `type poolLocalInternal struct {` `private interface{} // Can be used only by the respective P.` `shared poolChain // Local P can pushHead/popHead; any P can popTail.` `}` `type poolLocal struct {` `poolLocalInternal` `// Prevents false sharing on widespread platforms with` `// 128 mod (cache line size) = 0 .` `pad [128 - unsafe.Sizeof(poolLocalInternal{})%128]byte` `}`
pushHead/popHeadpopTail
存取数据:
Put()
Get()getSlow()Get()
getSlow()
`func (p *Pool) getSlow(pid int) interface{} {` `// See the comment in pin regarding ordering of the loads.` `size := runtime_LoadAcquintptr(&p.localSize) // load-acquire` `locals := p.local // load-consume` `// Try to steal one element from other procs.` `for i := 0; i < int(size); i++ {` `l := indexLocal(locals, (pid+i+1)%int(size))` `if x, _ := l.shared.popTail(); x != nil {` `return x` `}` `}` `// Try the victim cache. We do this after attempting to steal` `// from all primary caches because we want objects in the` `// victim cache to age out if at all possible.` `size = atomic.LoadUintptr(&p.victimSize)` `if uintptr(pid) >= size {` `return nil` `}` `locals = p.victim` `l := indexLocal(locals, pid)` `if x := l.private; x != nil {` `l.private = nil` `return x` `}` `for i := 0; i < int(size); i++ {` `l := indexLocal(locals, (pid+i)%int(size))` `if x, _ := l.shared.popTail(); x != nil {` `return x` `}` `}` `// Mark the victim cache as empty for future gets don't bother` `// with it.` `atomic.StoreUintptr(&p.victimSize, 0)` `return nil` `}`
04
总结
sync.Poolsync.Pool
推荐阅读:
参考资料:
https://golang.org/pkg/sync/#...
https://golang.org/src/sync/p...
扫描二维码,加入微信群
点「赞」和「在看」是最大的支持👇
👇更多精彩内容,请点击「阅读原文」