I'm trying to loop through a list (e.g. sql rows) and fire go routines for each row. The issue is that the values passed to the function are not evaluated at the runtime so depending by how much time the function takes to execute it may use whatever value is on one of the next(s) rows instead the current one.
I'm aware that I could extract the function in a normal one and pass the arguments but I still want to share some global variables(to avoid many function arguments) thus the need to use an anonymous function. Still it's also confusing to me that the anonymous function takes variables from the environment while it's being executed because as far as I understand it is supposed to be executed in a separate routines just like & in unix programs, the communication being done only through channels.
The question is how do I make the anonymous function to receive a copy of vc
and use it during runtime ?
package main
import "fmt"
import "time"
type mystruct struct {
i int
s string
}
func main() {
vc := mystruct{}
vc.i = 1
vc.s = "hi"
gl := "this is global"
for i := 1; i < 4; i++ {
go func() {
vc.i++
time.Sleep(1 * time.Second)
fmt.Printf("row specific is %v, global is %v", vc, gl)
}()
}
time.Sleep(2 * time.Second)
}
I honestly don't understand what you're trying to achieve, however, if your only goal is to make a copy of the variable, you can just pass it to the go func like this:
for i := 1; i < 4; i++ {
go func(vc mystruct) {
vc.i++
//time.Sleep(1 * time.Second)
fmt.Printf("row specific is %v, global is %v
", vc, gl)
}(vc)
}
The code is accessing the same struct from multiple goroutines . You need to protect the struct with a mutex to govern the access to its value. Also you need to wait for all the goroutines to finish. Time.Sleep alone will not guarantee that. Use a Wait group. Here is a working example:
package main
import "fmt"
import "time"
import "strconv"
import "sync"
type mystruct struct {
i int
s string
m sync.Mutex
}
func main() {
vc := mystruct{}
vc.i = 1
vc.s = "hi"
var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
vc.m.Lock()
defer vc.m.Unlock()
defer wg.Done()
vc.i++
time.Sleep(1 * time.Millisecond)
vc.s = "good bye" + strconv.Itoa(vc.i)
fmt.Printf("%v
", vc)
}()
}
wg.Wait()
}
Playground: http://play.golang.org/p/K6rnQQSA1c
It seems the only way is to create the struct within the anonymous function and copy the closure value . See the code below. As @fabrizioM advised you should use wg if you need synchronisation. However the question was not about that thus I don't include the wg.
Still I'm not sure if it's safe as the the copy of vc
may take some time so edits/ improvements are still welcome
package main
import "fmt"
import "time"
type mystruct struct {
i int
s string
}
func main() {
vc := mystruct{}
vc.i = 1
vc.s = "hi"
for i := 1; i < 4; i++ {
go func() {
vc2 := vc
vc.i++
time.Sleep(1 * time.Second)
fmt.Printf("%v
", vc2)
}()
}
time.Sleep(2 * time.Second)
}