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

扫描二维码,加入微信群

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

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