все, уже месяц изучаю Голанг и сталкивался с этой проблемой.В основном я пытаюсь повторно использовать [] байт из 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)
}
}
Под моимimpression sync.Pool не выделяет новую память для байта [], но я вижу дополнительное выделение с m.pool.get()
здесь.
Benchmark_WriteSpan-12 30000000 47,6 нс / операционная 32 B / op1 allocs / op 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 нс / оп 0 B / оп 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 нс / оп. 160 B / оп 5 allocs / op
Похоже, что пул выделяет 32B в каждомнапишите, не следует ли повторно использовать один и тот же байт [] после первого получения?
Update @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)
Я не уверен, считается ли это свободным списком, поддерживаемым как часть недолговечного объекта, не могли бы вы быть более конкретным по этому поводу?