Потокобезопасна ли стандартная `map` в Go?

Ответ

Нет, стандартный тип map в Go не является потокобезопасным. Одновременная запись и чтение из map разными горутинами приведет к состоянию гонки (race condition), что может вызвать панику приложения или привести к непредсказуемым результатам.

Для обеспечения потокобезопасности при работе с map используются следующие подходы:

  1. sync.Mutex или sync.RWMutex: Классический способ защиты с помощью мьютекса. RWMutex предпочтительнее, когда количество чтений значительно превышает количество записей, так как он позволяет выполнять множество чтений одновременно.

    Пример с sync.RWMutex

    type SafeMap struct {
        mu sync.RWMutex
        m  map[string]int
    }
    
    func (s *SafeMap) Get(key string) (int, bool) {
        s.mu.RLock() // Блокировка на чтение
        defer s.mu.RUnlock()
        val, ok := s.m[key]
        return val, ok
    }
    
    func (s *SafeMap) Set(key string, value int) {
        s.mu.Lock() // Блокировка на запись
        defer s.mu.Unlock()
        s.m[key] = value
    }
  2. sync.Map: Специализированный тип, добавленный в Go 1.9. Он оптимизирован для сценариев, где ключ после записи редко изменяется или удаляется, а количество чтений велико. sync.Map позволяет избежать глобальной блокировки для большинства операций чтения, что делает его производительнее map с мьютексом в определенных условиях.