并发 Go 例程中的数据争用
此代码演示了并发 Go 例程中的数据争用问题:
package main import ( "fmt" "time" ) type field struct { name string } func (p *field) print() { fmt.Println(p.name) } func main() { data := []field{{"one"}, {"two"}, {"three"}} for _, v := range data { go v.print() } <-time.After(1 * time.Second) }
问题:
代码打印“三”三次,而不是按任意顺序打印“一”、“二”和“三”。这是因为存在数据竞争。
解释:
隐式地,代码在计算 goroutine 函数的参数时采用变量 v 的地址。 goroutine 函数 v.print() 相当于 (&v).print()。循环改变了 v 的值,当 goroutine 执行时,它们恰好具有循环的最后一个值(“三”)。
修复:
有多种方法可以解决此数据争用:
for _, v := range data { v := v // short variable declaration of new variable `v`. go v.print() }
data := []*field{{"one"}, {"two"}, {"three"}} // note '*' for _, v := range data { go v.print() }
data := []field{{"one"}, {"two"}, {"three"}} // note '*' for i := range data { v := &data[i] go v.print() }
for _, v := range data { go func(v field) { v.print() // take address of argument v, not range variable v. }(v) }
以上是在 Go 中启动 Goroutine 时如何避免数据竞争?的详细内容。更多信息请关注PHP中文网其他相关文章!