impressive17
@impressive17

Почему анонимная функция работает только с последним значением переменной?

Есть код
package main

import (
	"sync"
)

const N = 10

func main() {
	m := make(map[int]int)
      
	wg := &sync.WaitGroup{}
	mu := &sync.Mutex{}
	wg.Add(N)
	for i := 0; i < N; i++ {
                k:= 5
		go func() {
			defer wg.Done()
			mu.Lock()
                       println(i,k)
			m[i] = k
			mu.Unlock()
		}()
	}
	wg.Wait()
	println(len(m))
	println(m[0])

По выводу видно, что тут мы меняем только m[10]
Я понимаю, что чтобы проставить значиния всем индексам 0...9 нужно добавить i как аргумент анонимной функции, но не совсем понимаю почему. Понятно, если бы сохраняли состояние и вызывали потом эти анонимные функции потом, получая замыкание по сути. Но тут мы запускаем анонимные функции сразу, и так как они имеют доступ к контексту, в котором вызваны, кажется что i должны быть разные.
В чем фокус?
  • Вопрос задан
  • 497 просмотров
Решения вопроса 1
EvgenyMamonov
@EvgenyMamonov Куратор тега Go
Senior software developer, system architect
Тут суть в том, что в момент, когда анонимная функция начнёт выполняться - выполнение цикла к тому моменту уже закончится и i будет равна 10.
Т.е. шедулер не успевает запустить горутины, они фактически запускаются уже после цикла, но часть из них может успеть и во время цикла запуститься...

Самый простой способ получить желаемый результат передать значение как параметр
go func(idx int) {
    ...
}(i)


Полный пример:
package main

import (
    "sync"
)

const N = 10

func main() {
    m := make(map[int]int)
    wg := &sync.WaitGroup{}
    mu := &sync.Mutex{}
    wg.Add(N)
    for i := 0; i < N; i++ {
        k := 5
        go func(idx int) {
            defer wg.Done()
            mu.Lock()
            println(idx, k)
            m[idx] = k
            mu.Unlock()
        }(i)
    }
    wg.Wait()
    println(len(m))
    println(m[0])
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы