Назад к задачам
Junior — Senior
5

Проблема гонки данных при запуске горутин в цикле

Компании, где спрашивали:

Вкусвилл АвтомаконВкусвилл Автомакон
Получайте помощь с лайвкодингом в реальном времени с Sobes Copilot
Условие задачи

В этом примере показана типичная ошибка, когда несколько горутин одновременно используют переменную цикла. Какой именно баг присутствует в коде и какие способы позволяют избавиться от него?

func main(){
    for i := 0; i < 10: i++ {
        go func(){
            fmt.Println(i)
        }()
    }
}

Что происходит:

  • Цикл использует одну и ту же переменную i для всех итераций. К моменту выполнения анонимной функции значение i уже может измениться, поэтому горутины могут вывести одинаковые или «пропущенные» числа.
  • Кроме того, в заголовке цикла стоит двоеточие вместо точки с запятой, что делает код синтаксически неверным.

Как исправить:

  1. Передать текущий индекс в функцию как параметр. Это создаст отдельную копию значения для каждой горутины.
func main() {
    for idx := 0; idx < 10; idx++ {
        go func(v int) {
            fmt.Println(v)
        }(idx)
    }
}
  1. Локальная переменная внутри тела цикла.
func main() {
    for i := 0; i < 10; i++ {
        v := i // отдельная копия
        go func() {
            fmt.Println(v)
        }()
    }
}
  1. Синхронизация завершения горутин, например, через sync.WaitGroup, чтобы гарантировать вывод всех чисел до завершения программы.
func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(v int) {
            defer wg.Done()
            fmt.Println(v)
        }(i)
    }
    wg.Wait()
}

Эти приёмы устраняют состояние гонки и делают программу предсказуемой.