sync.Pool 比使用 channel 慢很多,那么我们为什么要使用 sync.Pool?
sync.Pool is much slower than using channel, so why should we use sync.Pool?
看了sync.Pool
设计,发现是两个逻辑,为什么要用localPool来解决锁竞争。我们可以直接用chan来实现一个。
使用通道比 sync.pool
快 4 倍!
pool除了可以clear object,还有什么优势?
这是池实现和基准测试代码:
package client
import (
"runtime"
"sync"
"testing"
)
type MPool chan interface{}
type A struct {
s string
b int
overflow *[2]*[]*string
}
var p = sync.Pool{
New: func() interface{} { return new(A) },
}
var mp MPool = make(chan interface{}, 100)
func get() interface{} {
select {
case r := <-mp:
return r
default:
return new(A)
}
}
func put(a interface{}) {
select {
case mp <- a:
default:
}
return
}
func pool() {
a := p.Get()
p.Put(a)
}
func init() {
runtime.GOMAXPROCS(8)
}
func BenchmarkName(b *testing.B) {
for i := 0; i < 20; i++ {
p.Put(new(A))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
go func() {
p.Put(p.Get())
}()
}
}
}
func BenchmarkNotPool(b *testing.B) {
for i := 0; i < 20; i++ {
put(new(A))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
a := get()
put(a)
}
}
}
您没有对同一事物进行基准测试,因此无法比较结果。
BenchmarkName()
启动的 goroutines 有很大的偷听,你甚至不需要等待这些 goroutines 完成,而 BenchmarkNotPool()
只是在同一个 goroutine 的池中获取和放入一个对象。
如果你修改 BenchmarkName()
做同样的事情,基准测试结果实际上表明它是另一种方式:sync.Pool
快了 3 倍多,这是真的,所以这就是它的用途/优势.
func BenchmarkName(b *testing.B) {
for i := 0; i < 20; i++ {
p.Put(new(A))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
p.Put(p.Get())
}
}
}
结果:
BenchmarkName-8 500000 2453 ns/op
BenchmarkNotPool-8 200000 7984 ns/op
另见相关问题:
看了sync.Pool
设计,发现是两个逻辑,为什么要用localPool来解决锁竞争。我们可以直接用chan来实现一个。
使用通道比 sync.pool
快 4 倍!
pool除了可以clear object,还有什么优势?
这是池实现和基准测试代码:
package client
import (
"runtime"
"sync"
"testing"
)
type MPool chan interface{}
type A struct {
s string
b int
overflow *[2]*[]*string
}
var p = sync.Pool{
New: func() interface{} { return new(A) },
}
var mp MPool = make(chan interface{}, 100)
func get() interface{} {
select {
case r := <-mp:
return r
default:
return new(A)
}
}
func put(a interface{}) {
select {
case mp <- a:
default:
}
return
}
func pool() {
a := p.Get()
p.Put(a)
}
func init() {
runtime.GOMAXPROCS(8)
}
func BenchmarkName(b *testing.B) {
for i := 0; i < 20; i++ {
p.Put(new(A))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
go func() {
p.Put(p.Get())
}()
}
}
}
func BenchmarkNotPool(b *testing.B) {
for i := 0; i < 20; i++ {
put(new(A))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
a := get()
put(a)
}
}
}
您没有对同一事物进行基准测试,因此无法比较结果。
BenchmarkName()
启动的 goroutines 有很大的偷听,你甚至不需要等待这些 goroutines 完成,而 BenchmarkNotPool()
只是在同一个 goroutine 的池中获取和放入一个对象。
如果你修改 BenchmarkName()
做同样的事情,基准测试结果实际上表明它是另一种方式:sync.Pool
快了 3 倍多,这是真的,所以这就是它的用途/优势.
func BenchmarkName(b *testing.B) {
for i := 0; i < 20; i++ {
p.Put(new(A))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
p.Put(p.Get())
}
}
}
结果:
BenchmarkName-8 500000 2453 ns/op
BenchmarkNotPool-8 200000 7984 ns/op
另见相关问题: