go - Go sync.pool 比 make 慢很多吗?

标签 go

我尝试使用sync.Pool 来重用[]byte。但事实证明它比 make 慢。代码:

package main

import (
    "sync"
    "testing"
)

func BenchmarkMakeStack(b *testing.B) {
    for N := 0; N < b.N; N++ {
        obj := make([]byte, 1024)
        _ = obj
    }
}

var bytePool = sync.Pool{
    New: func() interface{} {
        b := make([]byte, 1024)
        return &b
    },
}

func BenchmarkBytePool(b *testing.B) {
    for N := 0; N < b.N; N++ {
        obj := bytePool.Get().(*[]byte)
        _ = obj
        bytePool.Put(obj)
    }
}

结果:

$ go test pool_test.go -bench=. -benchmem
BenchmarkMakeStack-4    2000000000      0.29 ns/op       0 B/op    0 allocs/op
BenchmarkBytePool-4      100000000     17.2 ns/op        0 B/op    0 allocs/op

根据 Go 文档,sync.Pool 应该更快,但我的测试显示并非如此。谁能帮我解释一下?

更新: 1. 使用 go benchmark 更新有问题的代码。 2.答案放在stackheap,看peterSO的答案。

最佳答案

基准测试第一定律:无意义的微基准测试产生无意义的结果。

您不切实际的微基准测试没有意义。


Package sync

import "sync"

type Pool

A Pool is a set of temporary objects that may be individually saved and retrieved.

Any item stored in the Pool may be removed automatically at any time without notification. If the Pool holds the only reference when this happens, the item might be deallocated.

A Pool is safe for use by multiple goroutines simultaneously.

Pool's purpose is to cache allocated but unused items for later reuse, relieving pressure on the garbage collector. That is, it makes it easy to build efficient, thread-safe free lists. However, it is not suitable for all free lists.

An appropriate use of a Pool is to manage a group of temporary items silently shared among and potentially reused by concurrent independent clients of a package. Pool provides a way to amortize allocation overhead across many clients.

An example of good use of a Pool is in the fmt package, which maintains a dynamically-sized store of temporary output buffers. The store scales under load (when many goroutines are actively printing) and shrinks when quiescent.

On the other hand, a free list maintained as part of a short-lived object is not a suitable use for a Pool, since the overhead does not amortize well in that scenario. It is more efficient to have such objects implement their own free list.

sync.Pool 是否适合您的用例? sync.Pool 是否适合您的基准测试?您的用例和基准是否相同?您的用例是微基准测试吗?


使用 Go testing 包进行人工基准测试,使用单独的基准测试 make 堆栈和堆分配,make 既快又慢比 sync.Pool

输出:

$ go test pool_test.go -bench=. -benchmem
BenchmarkMakeStack-4    2000000000      0.29 ns/op       0 B/op    0 allocs/op
BenchmarkMakeHeap-4       10000000    136 ns/op       1024 B/op    1 allocs/op
BenchmarkBytePool-4      100000000     17.2 ns/op        0 B/op    0 allocs/op
$

pool_test.go:

package main

import (
    "sync"
    "testing"
)

func BenchmarkMakeStack(b *testing.B) {
    for N := 0; N < b.N; N++ {
        obj := make([]byte, 1024)
        _ = obj
    }
}

var obj []byte

func BenchmarkMakeHeap(b *testing.B) {
    for N := 0; N < b.N; N++ {
        obj = make([]byte, 1024)
        _ = obj
    }
}

var bytePool = sync.Pool{
    New: func() interface{} {
        b := make([]byte, 1024)
        return &b
    },
}

func BenchmarkBytePool(b *testing.B) {
    for N := 0; N < b.N; N++ {
        obj := bytePool.Get().(*[]byte)
        _ = obj
        bytePool.Put(obj)
    }
}

关于go - Go sync.pool 比 make 慢很多吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53613556/

相关文章:

pointers - 戈朗 : Why selector to pointers is illegal after comparison?

amazon-web-services - 我无法读取环境变量(Go 中的 aws-lambda)

algorithm - Go lang : search x digits from sets of numbers, 为什么需要很长时间才能执行?

具有不同(未知)字符串匹配的正则表达式

go - html/模板 : "layout" is undefined

google-app-engine - 具有接口(interface)类型字段的结构

go - 如何正确捕获所有 stdout/stderr

go - 在结构映射中实现结构集

go - Grafana/Prometheus 将多个 ip 可视化为查询

go - 将接口(interface)方法的参数限制为一些允许的结构?