gpt4 book ai didi

go - 从 goroutine 更改变量

转载 作者:数据小太阳 更新时间:2023-10-29 03:46:29 24 4
gpt4 key购买 nike

我尝试用 2 个 goroutines 编写示例程序来说明竞争条件。一个打印 x,另一个增量 x

package main

import (
"fmt"
"time"
)

func main() {
x := 0

go func() {
for {
if x%2 == 0 {
fmt.Println(x)
}
}
}()

go func() {
for {
x = x + 1
}
}()

<-time.After(1 * time.Second)
fmt.Println("final", x)
}

但是增量例程什么也不做,最后在 x 中保持为零。但是,如果增量例程添加 fmt.Println(x) 它会开始递增 x 并且程序按预期工作。

更新 #1:

这个简单示例的目的只是为了说明数据竞争问题。我知道在没有同步的情况下读取两个 goroutine 之间的共享变量是一个坏主意。请停下来向我指出这一点。我的问题是为什么增量 goroutine 在这里什么都不做?在我的世界观中应该稳步增加,但问题应该出现在读取 goroutine 中,结果可能无法确定,因为读取时 x 是一个,但打印时 x 可能是其他的。

更新#2:

我还有一个例子:

package main

import (
"time"
"fmt"
)

func main() {
x := 0

go func() {
last := x
for {
current := x
if last != current {
last = current
fmt.Println(last)
}
}
}()

go func() {
for {
//<-time.After(1 * time.Second) // if uncomment this row program start do "something"
x = x + 1
}
}()

<-time.After(10 * time.Second)
fmt.Println("final", x)
}

这个例子非常简单。一个例程递增计数器,如果更改则打印其他。该程序只有在写入 x = x+1 和读取 current := x 的情况下才会有未定义的行为,这不是原子操作,一个线程开始读取变量在另一个线程中写入和读取操作的中间将读取损坏的值。但是为什么在这种情况下,在增量例程程序中取消注释 sleep 时开始执行某些操作?

最佳答案

您有数据竞争:Go Data Race Detector .因此,您的结果未定义。


package main

import (
"fmt"
"time"
)

func main() {
x := 0

go func() {
for {
if x%2 == 0 {
//fmt.Println(x)
}
}
}()

go func() {
for {
x = x + 1
}
}()

<-time.After(1 * time.Second)
fmt.Println("final", x)
}

输出:

$ go run -race racer.go > /dev/null
==================
WARNING: DATA RACE
Write at 0x00c000088010 by goroutine 7:
main.main.func2()
/home/peter/gopath/src/racer.go:21 +0x4e

Previous read at 0x00c000088010 by goroutine 6:
main.main.func1()
/home/peter/gopath/src/racer.go:13 +0x38

Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:19 +0x9c

Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:11 +0x7a
==================
Found 1 data race(s)
exit status 66
$

package main

import (
"fmt"
"time"
)

func main() {
x := 0

go func() {
for {
if x%2 == 0 {
fmt.Println(x)
}
}
}()

go func() {
for {
x = x + 1
}
}()

<-time.After(1 * time.Second)
fmt.Println("final", x)
}

输出:

$ go run -race racer.go > /dev/null
==================
WARNING: DATA RACE
Read at 0x00c00008c010 by goroutine 6:
main.main.func1()
/home/peter/gopath/src/racer.go:13 +0x3c

Previous write at 0x00c00008c010 by goroutine 7:
main.main.func2()
/home/peter/gopath/src/racer.go:21 +0x4e

Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:11 +0x7a

Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:19 +0x9c
==================
==================
WARNING: DATA RACE
Write at 0x00c00008c010 by goroutine 7:
main.main.func2()
/home/peter/gopath/src/racer.go:21 +0x4e

Previous read at 0x00c00008c010 by goroutine 6:
main.main.func1()
/home/peter/gopath/src/racer.go:13 +0x3c

Goroutine 7 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:19 +0x9c

Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:11 +0x7a
==================
^Csignal: interrupt
$

关于go - 从 goroutine 更改变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51287810/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com