Реализация Pool на базе шаблона leaky buffer. Вообще, этот
шаблон правильнее называть leaky bucket, но в терминах Go используется
именно такое название.
Это решение имеет как преимущества, так и недостатки перед нативной реализацией sync.Pool: нативное решение более быстрое, но в противовес имеет серьёзный недостаток:
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.
Если вам понадобится хранить в пуле что-то, что не может быть подчищено автоматически GC, то вы получите утечку памяти. К таким объектам относятся, например cbyte арены, которые требуют ручного освобождения.
Во всём остальном этот пул работает аналогично нативному.
Метод Get пула аналогичен методу нативного пула и имеет сигнатуру:
func Get() anyМетод Put способен принять только те объекты, которые реализуют интерфейс Releaser:
type Releaser interface {
Release()
}
func Put(x Releaser) boolи также возвращает bool - протёк объект мимо ведра или нет.
Пул для использования требует инициализации через конструктор New:
func New(size uint, releaseFactor float64, options ...Option) Poolс аргументами:
size- Максимальный размер пула. По его достижении все новые поступающие элементы будет протекать.releaseFactor- Доля поступающих элементов, которые принудительно протекут мимо пула. Это нужно для постепенного обновления элементов в пуле.options- Список опциональных функций, которые позволяют задать дополнительные параметры пула.
В данный момент доступны три опциональные функции:
WithNewFn- Задаёт New функцию для конструирования объекта для возвращения вместоnilзначения.WithShards- Количество шардов пула, нужно для снижения нагрузки на мьютекс внутреннего канала.WithSampler- Задаёт сэмплер для оценки возвращать элемент в пул или нет. Может быть полезен для обновления содержимого пула.WithMetricsWriter- Подключает к пулу компонент для записи метрик.
import (
"github.com/koykov/lbpool"
"github.com/koykov/lbpool/metrics/victoria"
)
const (
poolSize = 100 // max pool size
releaseFactor = .05 // part of items that will leak independent of leaky logic
)
type item struct{...}
func (item) Release() {...}
var pool = lbpool.New(poolSize, releaseFactor, lbpool.WithNewFn(func() any { return &item{} }),
lbpool.WithMetricsWriter(victoria.NewWriter("my_pool)))
itm := pool.Get().(*item)
...
pool.Put(itm)Пул реализован поверх каналов Go и работает в несколько раз медленнее нативного пула:
BenchmarkPool-8 23870334 50.07 ns/op 0 B/op 0 allocs/op
BenchmarkPoolParallel-8 100000000 11.62 ns/op 0 B/op 0 allocs/op
BenchmarkPoolNative-8 100000000 10.59 ns/op 0 B/op 0 allocs/op
BenchmarkPoolNativeParallel-8 424538383 2.920 ns/op 0 B/op 0 allocs/opУчитывайте это при выборе инструментов под свои задачи.