# 0x103f77c sync.runtime_SemacquireMutex+0x3c /usr/local/go/src/runtime/sema.go:71
# 0x10714de sync.(*Mutex).Lock+0xfe /usr/local/go/src/sync/mutex.go:134
# 0x1071d8e sync.(*Pool).pinSlow+0x3e /usr/local/go/src/sync/pool.go:198
# 0x1071d25 sync.(*Pool).pin+0x55 /usr/local/go/src/sync/pool.go:191
# 0x1071a5e sync.(*Pool).Get+0x2e /usr/local/go/src/sync/pool.go:128
# 0x12feeb7 github.com/valyala/fasttemplate/vendor/github.com/valyala/bytebufferpool.(*Pool).Get+0x37 /Users/xargin/go/src/github.com/valyala/fasttemplate/vendor/github.com/valyala/bytebufferpool/pool.go:49
# 0x13005ef github.com/valyala/fasttemplate.(*Template).ExecuteFuncString+0x3f /Users/xargin/go/src/github.com/valyala/fasttemplate/template.go:278
# 0x13007c2 github.com/valyala/fasttemplate.(*Template).ExecuteString+0x52 /Users/xargin/go/src/github.com/valyala/fasttemplate/template.go:299
# 0x130107a main.loop.func1+0x3a /Users/xargin/test/go/http/httptest.go:22
有少量的 Goroutine 会阻塞在获取锁上,为什么呢?继续看看 sync.Pool 的 Get 流程:
func (p *Pool) Get() interface{} {
if race.Enabled {
race.Disable()
}
l := p.pin()
x := l.private
l.private = nil
runtime_procUnpin()
然后是 pin:
func (p *Pool) pin() *poolLocal {
pid := runtime_procPin()
s := atomic.LoadUintptr(&p.localSize) // load-acquire
l := p.local // load-consume
if uintptr(pid) < s {
return indexLocal(l, pid)
}
return p.pinSlow()
}
由于每一个对象的 sync.Pool 都是空的,所以 pin 的流程一定会走到 p.pinSlow:
func (p *Pool) pinSlow() *poolLocal {
runtime_procUnpin()
allPoolsMu.Lock()
defer allPoolsMu.Unlock()
pid := runtime_procPin()
而 pinSlow 中会用 allPoolsMu 来加锁,这个 allPoolsMu 主要是为了保护 allPools 变量:
var (
allPoolsMu Mutex
allPools []*Pool
)
在加了锁的状况下,会把用户重生成的 sync.Pool 对象 append 到 allPools 中:
if p.local == nil {
allPools = append(allPools, p)
}
(责任编辑:admin)