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

另见相关问题: