Вопрос проверяет понимание конкурентного доступа к map в Go и необходимости синхронизации с помощью мьютекса.
В Go встроенный тип map не предназначен для одновременного использования из нескольких горутин без дополнительной синхронизации. Если одна горутина пишет в map, а другая в это же время читает или пишет в ту же map, возникает состояние гонки (data race). Это может привести к неопределенному поведению: программа может упасть с паникой fatal error: concurrent map writes или concurrent map read and map write, либо данные будут повреждены.
Мьютекс (от англ. mutual exclusion — взаимное исключение) — это примитив синхронизации, который позволяет только одной горутине выполнять определенный участок кода (критическую секцию) в любой момент времени. Используя sync.Mutex, мы защищаем операции с map: перед чтением или записью горутина захватывает блокировку (Lock()), а после завершения освобождает её (Unlock()). Это гарантирует, что доступ к map будет последовательным и безопасным.
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
data := make(map[string]int)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
mu.Lock()
data[fmt.Sprintf("key%d", n)] = n
mu.Unlock()
}(i)
}
wg.Wait()
mu.Lock()
fmt.Println(data)
mu.Unlock()
}В этом примере 10 горутин пишут в map. Без мьютекса возникла бы гонка. С мьютексом каждая запись защищена, и программа работает корректно.
Для частого чтения и редкой записи можно использовать sync.RWMutex, который позволяет множеству горутин одновременно читать, но блокирует запись. Также в Go 1.9+ появился sync.Map — оптимизированная конкурентная map для специфических сценариев (например, когда ключи пишутся один раз и часто читаются).
Мьютекс необходим для безопасной работы с map в многопоточной среде Go. Он предотвращает состояние гонки и гарантирует целостность данных. Используйте sync.Mutex или sync.RWMutex при конкурентном доступе к map, если только вы не используете sync.Map в подходящем сценарии.