Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Задачи

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

AI info

Карта сайта

Документы

Медиа

Назад
Вопрос про Golang: Go, map, concurrency, sync.Mutex, sync.RWMutex, sync.Map

Как безопасно работать с map из нескольких горутин?

Проверяет понимание конкурентного доступа к map в Go и способов синхронизации.

Короткий ответ

В Go map не является потокобезопасной. Одновременная запись и чтение из map из разных горутин вызывает панику. Для безопасной работы нужно использовать мьютекс (sync.Mutex или sync.RWMutex) для синхронизации доступа, либо использовать специальную потокобезопасную структуру sync.Map, которая оптимизирована для сценариев с редкими записями и частыми чтениями.

Длинный ответ

Проблема конкурентного доступа к map

Встроенная map в Go не предназначена для одновременного использования из нескольких горутин. Если хотя бы одна горутина пишет в map, а другая в это же время читает или пишет, возникает race condition, который приводит к панике с сообщением "fatal error: concurrent map writes" или "concurrent map read and map write".

Решение с sync.Mutex

Самый простой и универсальный способ — защитить доступ к 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

Если чтений гораздо больше, чем записей, можно использовать 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
}

Готовое решение: sync.Map

В стандартной библиотеке 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 стоит применять только в специфических сценариях с высокой конкуренцией на чтение и редкими записями, так как её внутренняя реализация сложнее и может быть медленнее при простых операциях.

  • Аватар

    Golang Guru

    Maxim Lukyanov

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.

Уровень

  • Рейтинг:

    4

  • Сложность:

    5

Навыки

  • Golang

    Golang

Ключевые слова

#Go

#map

#concurrency

#sync.Mutex

#sync.RWMutex

#sync.Map

Подпишись на Golang Developer в телеграм

  • Аватар

    Golang Guru

    Maxim Lukyanov

    Guru – это эксперты YeaHub, которые помогают развивать комьюнити.