繁体   English   中英

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

[英]Why code in loop not executed when I have two go-routines

我在golang遇到问题

var a = 0
func main() {
        go func() {
                for {
                        a = a + 1
                }
        }()
        time.Sleep(time.Second)
        fmt.Printf("result=%d\n", a)
}
  • 预期:结果=(大整数)
  • 结果:result = 0

您有竞争条件,请使用-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()
}

在进行任何读写锁定互斥锁然后将其解锁之前,现在您没有任何竞争,因此重新加载将在最后结束。
有关更多信息,请阅读本主题。
Go(Golang)中的数据竞赛及其解决方法

Golang并发-数据竞赛

您的程序正在进入竞争状态。 go可以检测到这种情况。

假设您的文件名为main.go请尝试使用go run -race main.go运行程序。 它将显示种族如何发生,如何在goroutine中写入,如何通过主goroutine同时读取。 它也会按照您的预期打印一个随机的int数。

正如其他作者所提到的,您有一个数据竞赛,但是如果将此行为与使用pthreads用C编写的程序进行比较,则会丢失一些重要数据。 您的问题不仅在于时间安排,还在于语言定义。 因为并发原语是语言本身所固有的,所以Go语言内存模型( https://golang.org/ref/mem )准确描述了一个goroutine的更改时间和更改方式-将goroutines视为“超轻量用户空间”线程”,而且距离不会太远-保证对在另一个goroutine中运行的代码可见。

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

这类似于您将C中的局部int变量设置为1的情况,也许您有一个while循环在循环中读取该变量,等待ISR将其设置为0,然后再进行编译,变得太聪明了,因此决定将测试优化为零,因为它认为您的变量永远无法在循环内更改,而您实际上只是想进行无限循环,因此您必须将变量声明为volatile才能修复“ bug” 。

如果您要使用Go(我目前最喜欢的语言,FWIW)进行工作,则需要花一些时间阅读并彻底理解上面链接的Go内存模型,它将在将来真正获得回报。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM