Тип sync.Pool

Тип sync.Pool представляет собой пул временных объектов, которые могут быть переиспользованы для снижения количества выделений памяти и нагрузки на сборщик мусора. Пул безопасен для конкурентного использования из нескольких горутин. Основное предназначение sync.Pool - хранение объектов, создание которых требует значительных ресурсов, для их повторного использования. Пул автоматически удаляет объекты при необходимости.

Синтаксис

govar pool sync.Pool
pool.New = func() interface{} {
  return new(MyType)
}

Метод Get - получение объекта из пула

Метод Get возвращает объект из пула. Если в пуле нет объектов, то вызывается функция New для создания нового объекта. Возвращаемое значение имеет тип interface{}, поэтому его необходимо привести к нужному типу.

Метод Put - возвращение объекта в пул

Метод Put помещает объект обратно в пул для последующего переиспользования. После вызова Put объект может быть использован другим потребителем, поэтому не следует продолжать использовать объект после его возврата в пул.

Пример

Давайте создадим пул для переиспользования буферов bytes.Buffer:

gopackage main

import (
  "bytes"
  "fmt"
  "sync"
)

func main() {
  var pool = sync.Pool{
    New: func() interface{} {
      return new(bytes.Buffer)
    },
  }

  buf := pool.Get().(*bytes.Buffer)
  buf.WriteString("Hello, World!")
  fmt.Println(buf.String())

  buf.Reset()
  pool.Put(buf)
}

Результат выполнения кода:

go"Hello, World!"

Пример

Давайте рассмотрим пример с конкурентным использованием пула:

gopackage main

import (
  "fmt"
  "sync"
)

func main() {
  var pool = sync.Pool{
    New: func() interface{} {
      return make([]int, 0, 10)
    },
  }

  var wg sync.WaitGroup

  for i := 0; i < 3; i++ {
    wg.Add(1)
    go func(id int) {
      defer wg.Done()

      slice := pool.Get().([]int)
      slice = append(slice, id)
      fmt.Printf("Goroutine %d: %v\n", id, slice)

      slice = slice[:0]
      pool.Put(slice)
    }(i)
  }

  wg.Wait()
}

Результат выполнения кода:

go"Goroutine 2: [2]"
"Goroutine 0: [0]"
"Goroutine 1: [1]"

Пример

Давайте продемонстрируем, как sync.Pool автоматически очищает объекты при необходимости:

gopackage main

import (
  "fmt"
  "runtime"
  "sync"
)

func main() {
  var pool = sync.Pool{
    New: func() interface{} {
      return "new object"
    },
  }

  pool.Put("cached object")
  fmt.Println(pool.Get())
  fmt.Println(pool.Get())

  runtime.GC()
  fmt.Println(pool.Get())
}

Результат выполнения кода:

go"cached object"
"new object"
"new object"

Смотрите также

  • метод sync.Pool.Get,
    который получает объект из пула
  • метод sync.Pool.Put,
    который возвращает объект в пул
  • тип sync.Mutex,
    который обеспечивает взаимное исключение для доступа к данным
  • тип sync.WaitGroup,
    который ожидает завершения группы горутин