所有,现在一直在学习Golang一个月,并遇到了这个问题。基本上我正在尝试重用sync.Pool中的[]字节来进行一些散列。
我添加了一个最小可行样本,用于复制它:
type mWriter struct {
pool *sync.Pool
}
func (m *mWriter) writeSpan(span interface{}) {
haha := m.pool.Get().([]byte)
// in real code some actions here instead of simply setting haha[0] = 1
haha[0] = 1
m.pool.Put(haha)
}
func NewWriter() *mWriter {
bytepool := &sync.Pool{
New: func() interface{} {
return make([]byte, 16)
},
}
return &mWriter{
pool: bytepool,
}
}
func Benchmark_WriteSpan(b *testing.B) {
c := NewWriter()
b.ResetTimer()
b.ReportAllocs()
for it := 0; it < b.N; it++ {
c.writeSpan(nil)
}
}
在我的印象下,sync.Pool没有为[]字节分配新内存,但我在这里看到了m.pool.get()
的额外分配。
Benchmark_WriteSpan-12 30000000 47.6 ns / at 32 B / at 1 allocs / at PASS
这有什么解释?我在这里尝试了一些更简单的基准测试:
func Benchmark_2(b *testing.B) {
// Initializing pool
pool := &sync.Pool{
New: func() interface{} {
return make([]byte, 4)
},
}
b.ResetTimer()
b.ReportAllocs()
// Get hold of instance one
one := pool.Get().([]byte)
one[1] = 1
one[2] = 2
// Submit back the instance after using
pool.Put(one)
}
但这显示没有分配:
Benchmark_2-12 2000000000 0.00 ns / on 0 B / on 0 allocs / op
感谢任何帮助! (如果这不是sync.Pool的使用方式,有什么建议吗?)
编辑:
好的,我在writeSpan的基准测试中添加了一个简单的循环,现在它给出了以下基准:
func Benchmark_WriteSpan(b *testing.B) {
c := NewWriter()
b.ResetTimer()
b.ReportAllocs()
for it := 0; it < b.N; it++ {
for i := 0; i < 5; i++ {
c.writeSpan(nil)
}
}
}
Benchmark_WriteSpan-12 5000000 226 ns / at 160 B / at 5 allocs / op
看起来池在每次写入时分配32B,不应该在第一次获取后重复使用相同的byte []吗?
更新@JimB我确实在实际代码中有一些逻辑,它更新了字节切片和散列。如下:
byteSlice := ds.poolInstance.bytepool.Get().([]byte)
copy(byteSlice[:len(ds.hashSalt)], ds.hashSalt)
span.TraceID.MarshalTo(byteSlice[len(ds.hashSalt):])
hashVal := ds.hashBytes(byteSlice)
ds.poolInstance.bytepool.Put(byteSlice)
我不确定这是否算作作为短期对象的一部分维护的免费列表,你能否更具体一点?
我想我发现了背后的原因。在我的真实代码中,我曾经有过:
bytepool: &sync.Pool{
New: func() interface{} {
return make([]byte, length)
},
},
...
...
bytepool.Get().([]byte)
不知何故,当我改变它
bytepool: &sync.Pool{
New: func() interface{} {
byteP := make([]byte, length)
return &byteP
},
},
...
...
bytepool.Get().(*[]byte)
分配下降到0.很抱歉,人们看起来不是sync.Pool的问题,而是基础数据结构。谢谢你的评论!