К какой модели конкурентности относятся мьютексы и для чего они используются?

Ответ

Мьютексы (sync.Mutex) относятся к модели конкурентности на основе общей памяти (shared memory). В отличие от каналов, они не передают данные, а служат примитивом синхронизации для защиты разделяемых ресурсов.

Основное назначение мьютекса — гарантировать, что только одна горутина в один момент времени может получить доступ к определённому участку кода, называемому критической секцией. Это предотвращает состояния гонки (race conditions).

Принцип работы:

  1. mu.Lock(): Горутина "захватывает" мьютекс. Если он уже захвачен другой горутиной, текущая горутина блокируется и ждёт его освобождения.
  2. Критическая секция: Код, который работает с разделяемыми данными (например, чтение и запись в map или переменную).
  3. mu.Unlock(): Горутина "освобождает" мьютекс, позволяя другим ожидающим горутинам его захватить.

Идиоматическое использование с defer:
Чтобы гарантировать вызов Unlock() даже в случае паники, его принято вызывать через defer.

var mu sync.Mutex
var counter int

func increment() {
    mu.Lock() // Захватываем мьютекс
    defer mu.Unlock() // Гарантируем освобождение при выходе из функции

    // Критическая секция
    counter++
}

Важные моменты:

  • Deadlock (взаимная блокировка): Возможен, если горутина пытается захватить мьютекс, который она уже держит, или при неправильном порядке захвата нескольких мьютексов.
  • Производительность: Чрезмерное использование мьютексов может привести к снижению параллелизма, так как горутины будут простаивать в ожидании блокировки.
  • sync.RWMutex: Для сценариев, где чтений гораздо больше, чем записей, используется RWMutex. Он позволяет неограниченному числу горутин одновременно читать данные, но запись требует эксклюзивного доступа.