你们好,我是 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...

图片

扫描二维码,加入微信群

图片

点「赞」和「在看」是最大的支持👇

图片

👇更多精彩内容,请点击阅读原文」