关于sync.pool的使用,我这里先给大家说一下结论:
代码语言:javascript复制在高并发或者大量的数据请求的场景中,我们会遇到很多问题。
垃圾回收就是其中之一(garbage collection),为了减少优化GC,我们一般想到的方法就是能够让对象得以重用。
这就需要一个对象池来存储待回收对象,等待下次重用,从而减少对象产生数量。
我们可以把sync.Pool类型值看作是存放可被重复使用的值的容器。
此类容器是自动伸缩的、高效的,同时也是并发安全的。为了描述方便,我们也会把sync.Pool类型的值称为临时对象池,而把存于其中的值称为对象值。
这个类设计的目的是用来保存和复用临时对象,以减少内存分配,降低CG压力。
以上的条件都是在一个gc周期内。
sync.pool其实主要的功能是在一个gc的周期内复用保存在池子里面的变量。
下面我们看一下它们的使用,使用其实也非常简单,一个put,一个get。
代码语言:javascript复制package main
import (
"sync"
"fmt"
)
func main() {
//下面这个是一个很简单的例子,这就是最直接最有效的使用例子,只有put和get方式。
p := new(sync.Pool)
p.Put("a")
fmt.Println(p.Get())
}
下面我们来给一下例子来证明用这个性能好一些。
代码语言:javascript复制package test
import (
"testing"
"sync"
)
//注意命名规范 Benchmark 首字母大写的方法名 参数固定
func BenchmarkA(b *testing.B) {
for i := 0; i < b.N; i {
str := "aaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
go a(str, nil)
}
}
func BenchmarkB(b *testing.B) {
p := new(sync.Pool)
t := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
p.Put(t)
for i := 0; i < b.N; i {
go a(nil, p)
}
}
func a(s interface{}, p *sync.Pool) interface{} {
if s == nil {
return p.Get()
} else {
return s
}
}
上面的代码BenchmarkA 是定义普通的变量,通过并发协程去读。BenchmarkB是定义sync.pool里面写进去数据,通过并发协程去读,我们看看结果。
代码语言:javascript复制goarch: amd64
BenchmarkA-8 5000000 387 ns/op
BenchmarkB-8 5000000 353 ns/op
PASS
ok _/F_/WebServer/www/2017/safephp/go/study/middle_high/test 4.830s
压测结果,明显B方法性能好一点,当然我们如果不是高并发的情况下我们可以不适用sync.pool。sync.pool在高并发的情况下,优化代码的情况下是一种很好的思路。