Все темы
Тема 02

Синхронизация и sync

Разберись в теме, затем проверь понимание на задачах.

0/4 решено0%
К задачам

О чём этот блок

Каналы хороши для оркестрации — «передай работу, сообщи о завершении». Но когда речь идёт о защите общего состояния (счётчик, кэш, флаг инициализации), на первый план выходят примитивы пакета sync и sync/atomic. Этот блок строит навык, без которого не обойтись ни в одном сервисе: безопасно читать и менять данные из множества горутин, не превращая горячий путь в узкое место.

Ключевой принцип Go-сообщества: «Share memory by communicating» — но это не догма. Счётчик через канал, Mutex и atomic имеет разные накладные расходы. Для read-heavy кэша RWMutex допускает параллельные чтения, а atomic.Value может публиковать неизменяемые снимки. Выигрыш зависит от нагрузки и размера критических секций; его проверяют бенчмарком. Здесь вы учитесь выбирать инструмент под профиль нагрузки, а не по привычке.

Что вы научитесь делать

  • Защищать счётчик мьютексом и атомиком и понимать, когда какой быстрее.
  • Оптимизировать read-heavy структуры через sync.RWMutex (или copy-on-write).
  • Делать инициализацию идемпотентной и безопасной: ровно один запуск, общий результат для всех ожидающих (sync.Once).
  • Видеть, что happens-before гарантирует видимость записей между горутинами, а его отсутствие — это data race.
  • Понимать внутреннее устройство WaitGroup, реализовав его аналог на каналах и условиях.

Карта задач

  • 05 · Thread-safe Counter (Mutex vs atomic) — две реализации одного счётчика; цена блокировки против lock-free инкремента; контеншен под тысячами горутин.
  • 06 · Потокобезопасный кэш (95% reads) — оптимизация под read-heavy профиль: RWMutex против Mutex, разделение читателей и писателей.
  • 07 · Idempotent Initializer (sync.Once) — «выполнить ровно один раз»: все вызывающие ждут единственного запуска и получают один и тот же результат (включая ошибку).
  • 08 · WaitGroup своими руками — устройство барьера ожидания изнутри: синхронизация счётчика и пробуждение Wait() без sync.WaitGroup и без прямого atomic.

Связанные главы учебника

// Идиома блока: разделяем читателей и писателей под read-heavy нагрузкой.
func (c *Cache) Get(k string) (any, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    v, ok := c.m[k]
    return v, ok
}

Задачи темы 4