Проверяет понимание конкурентного доступа к map в Go и способов синхронизации.
Встроенная map в Go не предназначена для одновременного использования из нескольких горутин. Если хотя бы одна горутина пишет в map, а другая в это же время читает или пишет, возникает race condition, который приводит к панике с сообщением "fatal error: concurrent map writes" или "concurrent map read and map write".
Самый простой и универсальный способ — защитить доступ к map с помощью мьютекса. Это гарантирует, что только одна горутина может работать с map в любой момент времени.
type SafeMap struct {
mu sync.Mutex
data map[string]int
}
func (sm *SafeMap) Set(key string, value int) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.data[key] = value
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mu.Lock()
defer sm.mu.Unlock()
val, ok := sm.data[key]
return val, ok
}Если чтений гораздо больше, чем записей, можно использовать sync.RWMutex. Он позволяет нескольким горутинам одновременно читать данные, но блокирует всех при записи.
type SafeMap struct {
mu sync.RWMutex
data map[string]int
}
func (sm *SafeMap) Get(key string) (int, bool) {
sm.mu.RLock()
defer sm.mu.RUnlock()
val, ok := sm.data[key]
return val, ok
}
func (sm *SafeMap) Set(key string, value int) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.data[key] = value
}В стандартной библиотеке Go есть sync.Map — потокобезопасная map, оптимизированная для случаев, когда ключи записываются один раз, а читаются много раз, или когда несколько горутин читают, пишут и обновляют разные ключи. Она использует амортизированный подход с двумя внутренними map и атомарными операциями.
var m sync.Map
// Запись
m.Store("key", 42)
// Чтение
if val, ok := m.Load("key"); ok {
fmt.Println(val.(int))
}
// Удаление
m.Delete("key")
// Итерация (без блокировки всей map)
m.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true // продолжаем итерацию
})Для большинства случаев используйте sync.Mutex или sync.RWMutex с обычной map — это даёт полный контроль и предсказуемость. sync.Map стоит применять только в специфических сценариях с высокой конкуренцией на чтение и редкими записями, так как её внутренняя реализация сложнее и может быть медленнее при простых операциях.