为了账号安全,请及时绑定邮箱和手机立即绑定

为什么当我有两个 go 例程时循环中的代码未执行

为什么当我有两个 go 例程时循环中的代码未执行

Go
Qyouu 2023-06-26 16:53:12
我在 golang 中遇到问题var a = 0func main() {        go func() {                for {                        a = a + 1                }        }()        time.Sleep(time.Second)        fmt.Printf("result=%d\n", a)}预期:结果=(一个大的整数)结果:结果=0
查看完整描述

3 回答

?
守候你守候我

TA贡献1802条经验 获得超10个赞

您有竞争条件,请使用 -race 标志运行您的程序


go run -race main.go

==================

WARNING: DATA RACE

Read at 0x0000005e9600 by main goroutine:

  main.main()

      /home/jack/Project/GoProject/src/gitlab.com/hooshyar/GoNetworkLab/StackOVerflow/race/main.go:17 +0x6c


Previous write at 0x0000005e9600 by goroutine 6:

  main.main.func1()

      /home/jack/Project/GoProject/src/gitlab.com/hooshyar/GoNetworkLab/StackOVerflow/race/main.go:13 +0x56


Goroutine 6 (running) created at:

  main.main()

      /home/jack/Project/GoProject/src/gitlab.com/hooshyar/GoNetworkLab/StackOVerflow/race/main.go:11 +0x46

==================

result=119657339

Found 1 data race(s)

exit status 66


什么是解决方案?

有一些解决方案,一个解决方案是使用互斥体:


var a = 0

func main() {

    var mu sync.Mutex


    go func() {

        for {

            mu.Lock()

            a = a + 1

            mu.Unlock()

        }

    }()

    time.Sleep(3*time.Second)

    mu.Lock()

    fmt.Printf("result=%d\n", a)

    mu.Unlock()

}

在任何读写锁定互斥体然后解锁它之前,现在您没有任何竞争,并且结果将在最后为 big int 。


查看完整回答
反对 回复 2023-06-26
?
慕勒3428872

TA贡献1848条经验 获得超6个赞

存在数据竞争,但如果将此行为与使用 pthreads 用 C 编写的程序进行比较,则会丢失一些重要数据。您的问题不仅仅是时间问题,还与语言定义有关。由于并发原语已融入到语言本身中,因此 Go 语言内存模型 ( https://golang.org/ref/mem ) 准确地描述了一个 Goroutine 何时以及如何更改——将 Goroutine 视为“超轻量级用户空间”线程”,你不会离得太远——保证对另一个 goroutine 中运行的代码可见。

如果没有任何同步操作,例如通道发送/接收或sync.Mutex 锁定/解锁,Go 内存模型表示,您对该 goroutine 内的“a”所做的任何更改都不必对主 goroutine可见。而且,由于编译器知道这一点,因此可以自由地优化 for 循环中的几乎所有内容。或不。

这与 C 中的局部 int 变量设置为 1 时的情况类似,并且可能有一个 while 循环在循环中读取该变量,等待 ISR 将其设置为 0,但随后编译器变得太聪明并决定优化为零的测试,因为它认为你的变量在循环内永远不会改变,而你真的只是想要一个无限循环,所以你必须声明变量来volatile修复“错误”。

如果您打算使用 Go(我目前最喜欢的语言,FWIW)工作,请花时间阅读并彻底理解上面链接的 Go 内存模型,这将在未来真正得到回报。


查看完整回答
反对 回复 2023-06-26
?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

您的程序正在进入竞争状态。go可以检测到此类场景。

尝试运行您的程序,go run -race main.go假设您的文件名为main.go. 它将显示竞争如何发生,尝试在 Goroutine 内写入,并由主 Goroutine 同时读取。它还会按照您的预期打印一个随机 int 数字。


查看完整回答
反对 回复 2023-06-26
  • 3 回答
  • 0 关注
  • 179 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信