Какие примитивы синхронизации существуют кроме каналов в Go
Что проверяют
Знаете ли вы пакет синхронизации целиком и понимаете ли, что канал не всегда лучший выбор.
Как отвечать
Сначала оговорка по существу: девиз про общение вместо разделения памяти не означает, что каналы всегда предпочтительнее. Для защиты небольшого общего состояния мьютекс проще, быстрее и понятнее. Стандартная библиотека сама так делает.
Из пакета sync:
MutexиRWMutex: взаимное исключение, второй разделяет читателей и писателей и выигрывает при преобладании чтений;WaitGroup: ожидание завершения группы горутин;Once: гарантированно однократное выполнение, обычно для ленивой инициализации. Работает корректно даже при одновременном вызове из многих горутин;Cond: ожидание условия с оповещением. Нужен редко, обычно задача решается каналом;Pool: переиспользование временных объектов, чтобы снизить нагрузку на сборщик. Важно: это не кэш, объекты из него могут исчезнуть в любой момент;Map: специализированная карта для двух сценариев, когда ключ пишется один раз и много читается либо когда горутины работают с непересекающимися ключами. В остальных случаях медленнее обычной карты под мьютексом.
Из sync/atomic: атомарные операции над числами и указателями. Начиная с версии 1.19 есть удобные типы, у которых методы вызываются прямо на значении, и это заметно безопаснее старого варианта с указателями.
Отдельно context: формально не примитив синхронизации, но именно он передаёт сигнал отмены и ограничение времени по всему дереву вызовов.
Из расширений: errgroup для группы горутин с первой ошибкой и отменой, semaphore для ограничения одновременности, singleflight для схлопывания одинаковых параллельных запросов в один. Последний очень полезен против лавины запросов при истечении кэша.
Где спотыкаются
Считают, что каналы обязаны заменять мьютексы везде.
Используют специализированную карту по умолчанию.
Копируют структуру, содержащую мьютекс, и получают две независимые блокировки.
Не знают про схлопывание одинаковых запросов и городят его вручную.