С семантикой Go 1.22+ числа 0–9 печатаются по одному разу, но в произвольном порядке. При старой общей переменной i возможны гонка и повторы.
Как горутины обрабатывают переменную цикла при захвате
С семантикой Go 1.22+ числа 0–9 печатаются по одному разу, но в произвольном порядке. При старой общей переменной i возможны гонка и повторы.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Какой вывод будет у следующей программы?
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
fmt.Println(i)
wg.Done()
}()
}
wg.Wait()
}
Ответ
С семантикой Go 1.22+ числа 0–9 печатаются по одному разу, но в произвольном порядке. При старой общей переменной i возможны гонка и повторы.
WaitGroup обеспечивает завершение Println до выхода main, но не порядок. В старой семантике цикл изменяет общую i одновременно с чтением в горутинах.
Универсальное решение: go func(i int) { defer wg.Done(); fmt.Println(i) }(i). Новая семантика относится к объявленным переменным цикла и зависит от языковой версии модуля. Даже после исправления захвата порядок 0, 1, 2 и далее требует отдельной координации.