首页 >后端开发 >Golang >在 Go 中启动 Goroutine 时如何避免数据竞争?

在 Go 中启动 Goroutine 时如何避免数据竞争?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-12-08 17:37:11180浏览

How to Avoid Data Races When Launching Goroutines in Go?

并发 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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn