Логотип YeaHub

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

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

Тренажёр

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

Обучение

Навыки

Задачи

Войти

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

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

© 2026 YeaHub

AI info

Карта сайта

Документы

Медиа

Назад
Вопрос про Golang: Go, goroutine, map, race condition, concurrency

Что произойдёт, если один горутин итерируется по map, а другой параллельно добавляет в неё элементы?

Проверяет понимание конкурентного доступа к map в Go и отсутствия встроенной защиты от одновременной записи и чтения.

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

В Go map не является потокобезопасной. Если одна горутина читает map, а другая одновременно пишет в неё, возникает состояние гонки (data race). Это может привести к панике (fatal error: concurrent map read and map write) или неопределённому поведению. Для безопасного доступа используйте sync.Mutex или sync.RWMutex.

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

Конкурентный доступ к map в Go

В Go встроенный тип map не предназначен для одновременного использования из нескольких горутин без синхронизации. Если одна горутина выполняет итерацию по map (чтение), а другая параллельно добавляет или удаляет элементы (запись), возникает состояние гонки (data race).

Что именно происходит?

При обнаружении одновременного чтения и записи Go runtime может выбросить панику с сообщением вида: fatal error: concurrent map read and map write. Однако это не гарантируется — в некоторых случаях программа может работать некорректно без явной ошибки, что ещё опаснее, так как приводит к неопределённому поведению (чтение мусорных данных, повреждение структуры map).

Пример проблемы

package main

import (
	"fmt"
	"sync"
)

func main() {
	m := make(map[int]int)
	var wg sync.WaitGroup
	wg.Add(2)

	// Горутина-писатель
	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			m[i] = i
		}
	}()

	// Горутина-читатель
	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			_ = m[i]
		}
	}()

	wg.Wait()
	fmt.Println("done")
}

Этот код почти наверняка упадёт с паникой из-за конкурентного доступа.

Как правильно решить проблему?

Используйте механизмы синхронизации:

  • sync.Mutex — блокирует доступ на время чтения или записи.
  • sync.RWMutex — позволяет множеству читателей одновременно, но блокирует всех при записи.
package main

import (
	"fmt"
	"sync"
)

func main() {
	var mu sync.RWMutex
	m := make(map[int]int)
	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			mu.Lock()
			m[i] = i
			mu.Unlock()
		}
	}()

	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			mu.RLock()
			_ = m[i]
			mu.RUnlock()
		}
	}()

	wg.Wait()
	fmt.Println("done safely")
}

Также можно использовать sync.Map — специальную потокобезопасную версию map, оптимизированную для некоторых сценариев (например, когда ключи пишутся один раз, а читаются много раз).

Вывод

Никогда не читайте и не пишите в обычную map из разных горутин без синхронизации. Используйте sync.Mutex, sync.RWMutex или sync.Map для безопасного конкурентного доступа. Это критически важно для стабильности и предсказуемости многопоточных Go-программ.

  • Аватар

    Golang Guru

    Maxim Lukyanov

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

Уровень

  • Рейтинг:

    4

  • Сложность:

    5

Навыки

  • Golang

    Golang

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

#Go

#goroutine

#map

#race condition

#concurrency

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

  • Аватар

    Golang Guru

    Maxim Lukyanov

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