> Как использовать мьютексы для защиты мапы при параллельном доступе в Go (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Т-Банк

Стек: Go

> Пример ответа

Короткий ответ

Мьютекс защищает мапу от гонок данных при конкурентном доступе. Основной паттерн - sync.RWMutex: блокируем на запись через Lock()/Unlock() при изменении, на чтение через RLock()/RUnlock(). Важно блокировать не только запись, но и чтение, иначе чтение может увидеть частично изменённое состояние. Альтернатива - sync.Map для специфичных сценариев, но мьютекс проще и предсказуемее.

Подробное объяснение

Мапа в Go не потокобезопасна: одновременные чтение и запись, или две записи, приводят к панике fatal error: concurrent map writes или к неопределённому поведению. Мьютекс сериализует доступ.

sync.Mutex - базовый вариант: блокирует и чтение, и запись. sync.RWMutex - оптимизация: позволяет множеству читателей одновременно, но писатель эксклюзивен. Это важно для сценариев read-heavy.

Критическая секция должна быть минимальной: не держите мьютекс во время I/O, сетевых вызовов или тяжёлых вычислений. Иначе вы убиваете конкурентность.

Паттерн защиты: мапа и мьютекс объявляются рядом, как единая структура. Это инкапсулирует логику и предотвращает случайный доступ без блокировки.

Также стоит учитывать: RLock не гарантирует отсутствие гонок с писателем, если писатель уже ждёт Lock - новые читатели могут "пролезть" вперёд (writer starvation). В Go это решено, но на практике редкие случаи возможны.

На практике

Для большинства случаев используйте sync.RWMutex внутри структуры. Методы структуры - Get, Set, Delete - сами управляют блокировками. Это скрывает детали от вызывающего кода.

Если мапа маленькая и операции быстрые - sync.Mutex достаточно. Если мапа большая и чтений много - RWMutex даст выигрыш.

sync.Map оправдан только когда: ключи стабильны (не перезаписываются), или есть паттерн "write-once, read-many", или разные goroutines работают с разными ключами. В остальных случаях мьютекс проще и быстрее.

Не копируйте мьютекс после использования - это приведёт к deadlock или гонкам. Передавайте указатель на структуру.

Пример кода

GO
type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func NewSafeMap() *SafeMap {
return &SafeMap{m: make(map[string]int)}
}
func (s *SafeMap) Get(key string) (int, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
v, ok := s.m[key]
return v, ok
}
func (s *SafeMap) Set(key string, value int) {
s.mu.Lock()
defer s.mu.Unlock()
s.m[key] = value
}
func (s *SafeMap) Delete(key string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.m, key)
}

Использование:

GO
sm := NewSafeMap()
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
sm.Set(fmt.Sprintf("key%d", n), n)
}(i)
}
wg.Wait()

Как отвечать на собеседовании

Начните с проблемы: мапа не потокобезопасна, гонки данных. Затем объясните выбор между Mutex и RWMutex, обоснуйте через сценарий. Покажите код структуры с инкапсуляцией. Упомяните, что блокировка должна быть короткой, и что defer для Unlock - стандарт. Если спросят про sync.Map - сравните по критериям: частота записи, паттерн доступа, сложность. Не углубляйтесь в детали реализации рантайма, если не просят.

Что проверяет интервьюер

  • Понимание гонок данных и почему мапа небезопасна.
  • Умение выбрать правильный примитив синхронизации.
  • Знание паттерна инкапсуляции мьютекса с данными.
  • Понимание trade-off между Mutex и RWMutex.
  • Осознание важности минимизации критической секции.
  • Умение объяснить, когда sync.Map уместен, а когда нет.

Типичные ошибки

  • Защита только записи, но не чтения - чтение без блокировки даёт гонку.
  • Копирование структуры с мьютексом - после копирования мьютекс не работает.
  • Держать мьютекс во время внешних вызовов - деградация производительности.
  • Использовать sync.Map везде "на всякий случай" - это не серебряная пуля.
  • Забыть defer и не разблокировать при панике - deadlock.
  • Блокировать Lock() внутри RLock() - взаимная блокировка.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью