首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Go sync.pool比make慢得多吗?

Go sync.pool比make慢得多吗?
EN

Stack Overflow用户
提问于 2018-12-04 12:58:53
回答 1查看 2.1K关注 0票数 1

我试图使用sync.Pool重用[]byte。但事实证明它比单纯的制造要慢得多。代码:

代码语言:javascript
复制
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)
    }
}

结果:

代码语言:javascript
复制
$ 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基准测试更新有问题的代码。2. 堆栈中的答案,参见peterSO的答案。

EN

回答 1

Stack Overflow用户

发布于 2018-12-04 13:42:39

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

你不切实际的微基准是没有意义的。

包同步 导入“同步” 类型池 池是一组临时对象,可以单独保存和检索。 存储在池中的任何项目可以在任何时候自动删除,无需通知。如果在发生这种情况时池保存了唯一的引用,则项目可能会被解除分配。 一个池是安全的,供多个峡谷同时使用。 池的目的是缓存已分配但未使用的项以供以后重用,从而减轻垃圾收集器的压力。也就是说,它使得构建高效的、线程安全的自由列表变得更加容易。然而,它并不适合所有的自由列表。 池的适当使用是管理一组临时项,这些临时项在包的并发独立客户端之间默默地共享,并可能被重用。池提供了一种方法来摊销许多客户端的分配开销。 一个很好地使用池的例子是fmt包,它维护一个动态大小的临时输出缓冲区存储。商店的规模在负荷下(当许多猩猩正在积极印刷),当静止时缩小。 另一方面,作为短期对象的一部分维护的空闲列表并不适合池的使用,因为在这种情况下,开销并不能很好地摊销。让这样的对象实现自己的自由列表更有效。

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

使用Go testing包进行人工基准测试,为make堆栈和堆分配提供单独的基准测试,makesync.Pool更快也更慢。

输出:

代码语言:javascript
复制
$ 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

代码语言:javascript
复制
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)
    }
}
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53613556

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档