🧩 Синхронизация в Go: Mutex и WaitGroup
Конкурентные программы могут одновременно обращаться к одним и тем же данным. Без синхронизации это приводит к гонкам данных и непредсказуемому поведению.
Go предоставляет два ключевых инструмента синхронизации: - Mutex - защита общих данных
- WaitGroup - ожидание завершения горутин
🔒 Mutex (мьютекс)
Mutex гарантирует, что в критическую секцию попадёт только одна горутина.
Как работает мьютекс:
Lock()- блокирует доступUnlock()- разблокирует- остальные горутины ждут освобождения
Пример защищённой структуры
type SyncedData struct {
inner map[string]int
mutex sync.Mutex
}
func (d *SyncedData) Insert(k string, v int) {
d.mutex.Lock()
defer d.mutex.Unlock()
d.inner[k] = v
}
func (d *SyncedData) Get(k string) int {
d.mutex.Lock()
defer d.mutex.Unlock()
return d.inner[k]
}
defer гарантирует разблокировку даже при ошибках.
🧯 Зачем использовать defer с Mutex?
Без defer:
d.mutex.Lock()
if somethingBad {
return // забыли Unlock → deadlock
}
d.mutex.Unlock()
С defer:
d.mutex.Lock()
defer d.mutex.Unlock()
Никаких утечек блокировок.
🔄 WaitGroup - ожидание горутин
WaitGroup позволяет дождаться завершения всех конкурентных задач.
Правила использования
Add(n)- сколько горутин будет запущеноDone()- горутина завершенаWait()- блокирует выполнение до завершения всех задач
Пример
var wg sync.WaitGroup
sum := 0
for i := 0; i < 20; i++ {
wg.Add(1)
value := i
go func() {
defer wg.Done()
sum += value
}()
}
wg.Wait()
fmt.Println("sum =", sum)
🧠 Итоги
- Mutex защищает общие данные от одновременной записи
- defer делает использование мьютекса безопасным
- WaitGroup позволяет дождаться завершения всех горутин
- Эти механизмы - фундамент безопасной конкурентности в Go