Метод sync.Pool.Get
Метод sync.Pool.Get извлекает объект из пула.
Если в пуле есть доступные объекты, метод возвращает один из них.
Если пул пуст, метод вызывает функцию New, указанную при создании
пула, и возвращает созданный объект.
Метод возвращает значение типа interface{}, поэтому результат
требует приведения к нужному типу.
Синтаксис
pool.Get()
Пример
Давайте создадим пул для объектов типа bytes.Buffer и получим объект из пула:
package main
import (
"bytes"
"fmt"
"sync"
)
func main() {
pool := &sync.Pool{
New: func() interface{} {
return bytes.NewBuffer([]byte{})
},
}
buf := pool.Get().(*bytes.Buffer)
defer pool.Put(buf)
buf.WriteString("Hello, World!")
fmt.Println(buf.String())
}
Результат выполнения кода:
"Hello, World!"
В этом примере мы создаем пул с функцией New, которая создает новый буфер.
Метод Get возвращает объект из пула или создает новый через New,
после чего мы используем буфер для записи строки.
Пример
Давайте рассмотрим, как работает получение объектов при наличии и отсутствии объектов в пуле:
package main
import (
"fmt"
"sync"
)
func main() {
pool := &sync.Pool{
New: func() interface{} {
return 0
},
}
// Пул пуст - Get создает новый объект
val1 := pool.Get().(int)
fmt.Println(val1)
// Помещаем объект обратно в пул
pool.Put(42)
// Get возвращает существующий объект
val2 := pool.Get().(int)
fmt.Println(val2)
// Пул снова пуст - создается новый объект
val3 := pool.Get().(int)
fmt.Println(val3)
}
Результат выполнения кода:
0
42
0
При первом вызове пул пуст, поэтому создается новый объект через New.
После помещения объекта в пул, метод Get возвращает его.
После повторного извлечения пул становится пустым, и снова создается новый объект.
Пример
Давайте рассмотрим практический пример с обработкой большого количества данных:
package main
import (
"fmt"
"sync"
)
type Data struct {
value int
}
func main() {
pool := &sync.Pool{
New: func() interface{} {
return &Data{}
},
}
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
// Получаем объект из пула
data := pool.Get().(*Data)
defer pool.Put(data)
// Используем объект
data.value = id
fmt.Printf("goroutine %d: data.value = %d\n", id, data.value)
}(i)
}
wg.Wait()
}
Результат выполнения кода (порядок может варьироваться):
"goroutine 9: data.value = 9"
"goroutine 0: data.value = 0"
"goroutine 1: data.value = 1"
"goroutine 2: data.value = 2"
"goroutine 3: data.value = 3"
"goroutine 4: data.value = 4"
"goroutine 5: data.value = 5"
"goroutine 6: data.value = 6"
"goroutine 7: data.value = 7"
"goroutine 8: data.value = 8"
В этом примере несколько горутин используют sync.Pool для получения объектов.
Метод Get возвращает объект, который может быть ранее использован другой горутиной,
поэтому важно правильно его сбросить перед использованием.
Смотрите также
-
метод
sync.Pool.Put,
который возвращает объект обратно в пул -
тип
sync.Pool,
предоставляющий пул временных объектов -
механизм
горутин,
которые часто используют пулы для оптимизации -
пакет
sync,
содержащий примитивы синхронизации