我正在尝试遍历列表(例如sql行)并为每行触发例程。问题是传递给函数的值不会在运行时计算,因此取决于函数执行它所花费的时间,可以使用下一行(而不是当前行)中的任何值。
我知道我可以在普通函数中提取函数并传递参数但我仍然想要共享一些全局变量(以避免许多函数参数),因此需要使用匿名函数。 仍然让我感到困惑的是,匿名函数在执行时从环境中获取变量,因为据我所知,它应该在一个单独的例程中执行,就像&在unix程序中,通信仅通过通道完成。
问题是如何让匿名函数接收vc
的副本并在运行时使用它?
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)
}
答案 0 :(得分:2)
代码从多个goroutines访问相同的结构。 您需要使用互斥锁来保护结构,以控制对其值的访问。 你还需要等待所有的goroutine完成。 Time.Sleep一个人不能保证。使用等待组。这是一个有效的例子:
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 \n", vc)
}()
}
wg.Wait()
}
答案 1 :(得分:0)
老实说,我不明白你想要实现的目标,但是,如果你的唯一目标是制作变量的副本,你可以将其传递给像this这样的go func:
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\n", vc, gl)
}(vc)
}
答案 2 :(得分:-2)
似乎唯一的方法是在匿名函数中创建结构并复制闭包值。请参阅下面的代码。正如@fabrizioM建议你如果需要同步就应该使用wg。然而问题不在于此,因此我不包括wg。
我仍然不确定它是否安全,因为vc
的副本可能需要一些时间,因此仍然欢迎编辑/改进
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\n", vc2)
}()
}
time.Sleep(2 * time.Second)
}