Пакет sync предлагает не только мьютексы и WaitGroup. Map, Once и Pool полезны в конкретных случаях, но каждый имеет свою цену и ограничения.

sync.Map

Map подходит для чтения без общей блокировки:

var sessions sync.Map
value, ok := sessions.Load(sessionID)

Чтение и запись безопасны, но составная операция снова требует согласования. LoadOrStore атомарен, LoadAndDelete тоже, а Load + Store после проверки уже нет.

Типичные применения:

  • редко меняющийся справочник со многими читателями;
  • независимые ключи без общего инварианта;
  • кэш, где нельзя блокировать весь map на чтении.

Для массива заказов или связанного состояния обычный map под RWMutex понятнее. sync.Map не даёт транзакции над несколькими ключами.

Once

Once выполняет инициализацию ровно один раз:

var once sync.Once
var repository *Repository

func Repo() *Repository {
    once.Do(func() {
        repository = openRepository()
    })
    return repository
}

Все вызовы ждут завершения первого. Если функция паникует, Once считается использованным: следующий вызов не повторит инициализацию. Ошибку, которую можно повторить, хранят отдельно и явно решают, допустим ли повтор.

Once не подходит для lazy value, которое нужно сбросить или обновить. Для этого есть OnceFunc и OnceValue, но повторная записная модель остаётся ограниченной.

Pool

Pool переиспользует временные объекты:

var buffers = sync.Pool{
    New: func() any { return new(bytes.Buffer) },
}

func encode() string {
    buffer := buffers.Get().(*bytes.Buffer)
    defer func() {
        buffer.Reset()
        buffers.Put(buffer)
    }()
    return buffer.String()
}

Reset обязателен: следующий пользователь не должен увидеть старые данные. Пул не ограничен и не является кэшем. Объект может исчезнуть после GC, поэтому нельзя полагаться на него для хранения.

Используют Pool после профиля, когда аллокации однотипных объектов действительно стоят дорого. Для маленьких значений он усложняет код и может ухудшить результат.

Коротко

  • sync.Map хорош для независимых ключей и частого чтения, не для составного состояния.
  • Once гарантирует одну инициализацию, но не повтор после паники.
  • Pool только сглаживает аллокации и не хранит объекты.
  • Переиспользуемое значение очищают перед возвратом в пул.