sync.pool_test
Created: July 16, 2021 12:53 AM
上一篇文章简单的聊了一下对于sync.pool的粗浅的理解,如果想要知道sync.pool怎么使用,最简单的方法就是看下官方的test是怎么用的,我们就官方的test来看看。
func TestPool(t *testing.T) {
// disable GC so we can control when it happens.
defer debug.SetGCPercent(debug.SetGCPercent(-1))
var p Pool
if p.Get() != nil {
t.Fatal("expected empty")
}
// Make sure that the goroutine doesn't migrate to another P
// between Put and Get calls.
Runtime_procPin()
p.Put("a")
p.Put("b")
if g := p.Get(); g != "a" {
t.Fatalf("got %#v; want a", g)
}
if g := p.Get(); g != "b" {
t.Fatalf("got %#v; want b", g)
}
if g := p.Get(); g != nil {
t.Fatalf("got %#v; want nil", g)
}
Runtime_procUnpin()
// Put in a large number of objects so they spill into
// stealable space.
for i := 0; i < 100; i++ {
p.Put("c")
}
// After one GC, the victim cache should keep them alive.
runtime.GC()
if g := p.Get(); g != "c" {
t.Fatalf("got %#v; want c after GC", g)
}
// A second GC should drop the victim cache.
runtime.GC()
if g := p.Get(); g != nil {
t.Fatalf("got %#v; want nil after second GC", g)
}
}
在代码中可以看出,在使用的时候将当前的G用Runtime_procPin()将P绑定住,避免在调用call()和put()时,G运行在另一个P上。首先p.Get()判断首先保证了p的local或者victim中都没有数据,随后使用put()存入两个数据,在函数开头的时候关闭了gc,所以现在数据是存在local里面的,然后使用Get()方法取出,因为lcoal是一个双端链表,一边是入另一边是出,所以Get()可以按照放入数据顺序依次取出,随后解绑当前G与P。
调用Put()存入数据,随后手动触发gc,那么依据上篇文章所说原本的数据就会被放到victim中,此时调用Get()也能取到数据,此时再触发gc的话刚刚victim中的数据就会被清除。
func TestPoolNew(t *testing.T) {
// disable GC so we can control when it happens.
defer debug.SetGCPercent(debug.SetGCPercent(-1))
i := 0
p := Pool{
New: func() interface{} {
i++
return i
},
}
if v := p.Get(); v != 1 {
t.Fatalf("got %v; want 1", v)
}
if v := p.Get(); v != 2 {
t.Fatalf("got %v; want 2", v)
}
// Make sure that the goroutine doesn't migrate to another P
// between Put and Get calls.
Runtime_procPin()
p.Put(42)
if v := p.Get(); v != 42 {
t.Fatalf("got %v; want 42", v)
}
Runtime_procUnpin()
if v := p.Get(); v != 3 {
t.Fatalf("got %v; want 3", v)
}
}
这个是关于pool的New函数的用例,我们先看下New函数的定义。
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{}
}
官方注释是说New()是一个可选项,如果调用Get()方法,如果没有存入的对象,那么就会调用New()方法,并返回New()的返回值,否则的话就会返回nil。调用Get并不会同时调用New()。所以New()的调用只会发生在Get没有值的之后。
测试用例中前两次调用都没有值,所以New()函数内部对i进行了自增,之后存入一个值再取出一个值,再取值,会再次调用New(),此时的i的值就是3.
基本只要掌握以上方法就可以使用sync.pool了,如果有说错的地方,请大家指出,不吝赐教,谢谢。
网友评论