sync 包(五):临时对象池 sync.Pool

前面我们已经陆续介绍了 sync 包提供的各种同步工具,比如互斥锁、条件变量、原子操作、多协程协作等,今天我们来看另外一种工具。

在高并发场景下,我们会遇到很多问题,垃圾回收(GC)就是其中之一。Go 语言中的垃圾回收是自动执行的,这有利有弊,好处是避免了程序员手动对垃圾进行回收,简化了代码编写和维护,坏处是垃圾回收的时机无处不在,这在无形之中增加了系统运行时开销。在对系统性能要求较高的高并发场景下,这是我们应该主动去避免的,因此这需要对对象进行重复利用,以避免产生太多垃圾,而这也就引入了我们今天要讨论的主题 —— 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

	// 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{}
}
PutGetsync.PoolPutinterface{}Getinterface{}GetGetNewNewGetnil

下面我们来看个简单的示例代码:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var pool = &sync.Pool{
        New: func() interface{} {
            return "Hello,World!"
        },
    }
    value := "Hello,学院君!"
    pool.Put(value)
    fmt.Println(pool.Get())
    fmt.Println(pool.Get())
}
poolNewfunc() interface{}PutpoolGetpoolGetNew
sync.Poolsync.PoolPool
package main

import (
    "fmt"
    "sync"
)

func test_put(pool *sync.Pool, deferFunc func())  {
    defer func() {
        deferFunc()
    }()
    value := "Hello,学院君!"
    pool.Put(value)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    var pool = &sync.Pool{
        New: func() interface{} {
            return "Hello,World!"
        },
    }
    go test_put(pool, wg.Done)
    wg.Wait()
    fmt.Println(pool.Get())
}
fmt.Printlnsync.Poolprinterprinter
func newPrinter() *pp {
    p := ppFree.Get().(*pp)
    p.panicking = false
    p.erroring = false
    p.fmt.init(&p.buf)
    return p
}

func (p *pp) free() {
    if cap(p.buf) > 64<<10 {
        return
    }
    
    p.buf = p.buf[:0]
    p.arg = nil
    p.value = reflect.Value{}
    ppFree.Put(p)
}
ppFreesync.Pool
var ppFree = sync.Pool{
    New: func() interface{} { return new(pp) },
}
sync.Pool