неожиданное sync.Pool распределения - PullRequest
0 голосов
/ 22 февраля 2019

все, уже месяц изучаю Голанг и сталкивался с этой проблемой.В основном я пытаюсь повторно использовать [] байт из 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)

Я не уверен, считается ли это свободным списком, поддерживаемым как часть недолговечного объекта, не могли бы вы быть более конкретным по этому поводу?

1 Ответ

0 голосов
/ 22 февраля 2019

Я думаю, что выяснил причину этого.В моем реальном коде я имел обыкновение иметь:

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. Так что извините, ребята, похоже, не проблема с синхронизацией.Pool, но основная структура данных.Спасибо за ваши комментарии, хотя!

...