博主vx: haitangyijiusu 。很高兴认识你!偶尔带huo,都是精挑细选信得过的产品,欢迎来支持,期待和您相遇!
1、part1 一个例子
p := pool.Get().(*Person)
fmt.Printf("第一次从pool里拿对象, %+v \n", p)
p.Name = "HanMeiMei"
pool.Put(p)
fmt.Printf("pool里已经有一个对象, %+v \n", pool.Get().(*Person))
fmt.Printf("pool里已经没有对象了, %+v \n", pool.Get().(*Person))
L()
2、part2 golang里fmt.Printf如何使用sync.Pool
fmt.Printf中Printf对应的函数是:
func Printf(format string, a ...interface{}) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}
继续看Fprintf函数:
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n, err = w.Write(p.buf)
p.free()
return
}
Fprintf第一个参数是io.Writer,Printf函数里传的是os.Stdout,相当于直接输出到标准输出。这里的newPrinter就是调用的Pool,
拿到pp指针之后,首先是做了一些format操作。并且将p.buf的内容写到w,调用free()函数将p重新归还到pool里。归还之前将p的部分字段重置,以便于其它代码再次拿到这个对象时是“干净”的。
其中newPrinter对应的函数体是
func newPrinter() *pp {
p := ppFree.Get().(*pp)
p.panicking = false
p.erroring = false
p.wrapErrs = false
p.fmt.init(&p.buf)
return p
}
函数体里ppFree是一个变量,对应一个sync.Pool
var ppFree = sync.Pool{
New: func() interface{} { return new(pp) },
}
结构体pp保存了一个打印对象的状态并且被sync.Pool重用以防止出现内存分配瓶颈。
接下来我们看一下pool_test.go的TestPoolNew函数 在src/sync/pool_test.go
func TestPoolNew(t *testing.T) {
// disable GC so we can control when it happens.
// 首先设置了GC=-1,就是不去做GC
defer debug.SetGCPercent(debug.SetGCPercent(-1))
i := 0
p := Pool{
New: func() interface{} {
i++
return i
},
}
// 此时pool里为空,连续调用两次Get,会返回1、2
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)
}
// 防止goroutine被抢占,目的是保护接下来的Put和Get操作都是同一个P的池子
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)
}
}
type PoolDequeue interface {
PushHead(val interface{}) bool
PopHead() (interface{}, bool)
PopTail() (interface{}, bool)
}
PoolDequeue 是一个双端队列,可以从头入队元素也可以从头、尾出队元素。
3、 gin框架也用到了sync.Pool
github.com\gin-gonic\gin\gin.go
func New() *Engine {
...
engine.pool.New = func() interface{} {
return engine.allocateContext()
}
}
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := engine.pool.Get().(*Context)
c.writermem.reset(w)
c.Request = req
c.reset()
engine.handleHTTPRequest(c)
engine.pool.Put(c)
}