Ответ
Мьютексы (sync.Mutex
) относятся к модели конкурентности на основе общей памяти (shared memory). В отличие от каналов, они не передают данные, а служат примитивом синхронизации для защиты разделяемых ресурсов.
Основное назначение мьютекса — гарантировать, что только одна горутина в один момент времени может получить доступ к определённому участку кода, называемому критической секцией. Это предотвращает состояния гонки (race conditions
).
Принцип работы:
mu.Lock()
: Горутина "захватывает" мьютекс. Если он уже захвачен другой горутиной, текущая горутина блокируется и ждёт его освобождения.- Критическая секция: Код, который работает с разделяемыми данными (например, чтение и запись в
map
или переменную). mu.Unlock()
: Горутина "освобождает" мьютекс, позволяя другим ожидающим горутинам его захватить.
Идиоматическое использование с defer
:
Чтобы гарантировать вызов Unlock()
даже в случае паники, его принято вызывать через defer
.
var mu sync.Mutex
var counter int
func increment() {
mu.Lock() // Захватываем мьютекс
defer mu.Unlock() // Гарантируем освобождение при выходе из функции
// Критическая секция
counter++
}
Важные моменты:
- Deadlock (взаимная блокировка): Возможен, если горутина пытается захватить мьютекс, который она уже держит, или при неправильном порядке захвата нескольких мьютексов.
- Производительность: Чрезмерное использование мьютексов может привести к снижению параллелизма, так как горутины будут простаивать в ожидании блокировки.
sync.RWMutex
: Для сценариев, где чтений гораздо больше, чем записей, используетсяRWMutex
. Он позволяет неограниченному числу горутин одновременно читать данные, но запись требует эксклюзивного доступа.