w3schools programacion funciones ejemplo closure autoejecutables anonimas go

go - programacion - Ir a concurrencia con for loop y la función anónima se comporta inesperadamente



funciones anonimas javascript (2)

Ya he encontrado una forma de que el código se comporte como yo quiero, pero me gustaría entender por qué se comporta así para que mi comprensión de la concurrencia de Go mejore.

Estaba probando sync.WaitGroup para esperar a que terminen algunos goroutines porque planeo hacer cargas múltiples a Amazon S3 de esta manera.

Este era el código que tenía originalmente:

func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) go func() { fmt.Println(i) time.Sleep(time.Second * 1) wg.Done() }() } wg.Wait() }

Me sorprendió ver que la salida fue: 6, 6, 6, 6, 6 .

En lugar de algo como: 2, 4, 1, 5, 3 .

Como el ciclo ni siquiera va a 6, esto no tiene sentido para mí. Más tarde pasé la variable i a la función anónima como argumento y luego se comportó como esperaba.

¿Por qué pasó esto? No lo entiendo


Esto está cubierto en la pregunta frecuente : ¿Qué sucede con los cierres que se ejecutan como goroutines?

En este caso, ninguno de los goroutines se programa hasta que complete el bucle for. Para que el bucle for se rompa, no debe ser menor o igual a 5, por lo tanto, es 6 en ese punto. Cuando se ejecutan los goroutines, cada uno imprime el valor de la variable individual i que se captura en los cierres.

Cuando pasa i como argumento a la función, copia el valor actual en una nueva variable, capturando el valor en ese momento.


Para responder a su pregunta, debe pasar a su func para que cada rutina tenga su propia copia del valor de i .

Entonces tu código debería verse así

func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) go func(i int) { fmt.Println(i) time.Sleep(time.Second * 1) wg.Done() }(i) } wg.Wait() }

Escribí esta función de utilidad para ayudar a paralelizar un grupo de funciones:

import "sync" // Parallelize parallelizes the function calls func Parallelize(functions ...func()) { var waitGroup sync.WaitGroup waitGroup.Add(len(functions)) defer waitGroup.Wait() for _, function := range functions { go func(copy func()) { defer waitGroup.Done() copy() }(function) } }

Entonces en tu caso, podríamos hacer esto

func main() { functions := []func(){} for i := 1; i <= 5; i++ { function := func(i int) func() { return func() { fmt.Println(i) } }(i) functions = append(functions, function) } Parallelize(functions...) fmt.Println("Done") }

Si desea utilizar la función Parallelize, puede encontrarla aquí https://github.com/shomali11/util