为什么在以下情况下使用两个 goroutine 时我的结构值不更新?
Why do my struct values not update in the following case when using two goroutines?
所以,我是 Go 的新手,上周末开始学习这门语言,并为 RPG 创建了一个基本的字符生成器/自动滚动器。
由于生成器会进行大量随机数滚动,直到达到某些值,我想我可能会使用 goroutines 来加快处理速度。
到目前为止,这是我最大的努力,但不知何故,在最终的 Printf 期间,我总是得到“STR: 0 DEX: 0”,即使我在调试期间可以看到两个并行函数正在正确设置值。
myCharacter 结构是在它们之外声明的,所以我认为更新它应该可以正常工作?
这是我糟糕的代码。我想要实现的是在并行 goroutine 中滚动“STR”和“DEX”,直到其中一个达到任意条件(这里的值都是 1000000,只是作为测试)。
任何人都可以帮我解决为什么 myCharacter.STR 和 myCharacter.DEX 最后打印为 0?
package main
import (
"fmt"
"math/rand"
"time"
)
type Character struct {
STR int
DEX int
}
func main() {
rand.Seed(time.Now().UTC().UnixNano())
QuitChan := make(chan bool)
myCharacter := new(Character)
go func() {
for {
select {
case <-QuitChan:
return
default:
mySTR, myDEX := RollChar()
if mySTR >= 1000000 && myDEX >= 1000000 {
myCharacter.STR = mySTR
myCharacter.DEX = myDEX
QuitChan <- true
return
}
}
}
}()
go func() {
for {
select {
case <-QuitChan:
return
default:
mySTR, myDEX := RollChar()
if mySTR >= 1000000 && myDEX >= 1000000 {
myCharacter.STR = mySTR
myCharacter.DEX = myDEX
QuitChan <- true
return
}
}
}
}()
fmt.Printf("STR: %d DEX: %d", myCharacter.STR, myCharacter.DEX)
}
func RollChar() (int, int) {
mySTR := rand.Intn(1000000) + 1
myDEX := rand.Intn(1000000) + 1
return mySTR, myDEX
}
您有一场数据竞赛。您的两个 goroutines 正在访问共享变量而没有任何显式同步。在这种情况下,您需要使用互斥锁来确保互斥以及在一个 goroutine 中所做的更改在其他 goroutine 中的可见性。
声明一个互斥量:
myCharacter := new(Character)
mutex:=sync.Mutex{}
在 read/write 共享变量时使用互斥体:
mutex.Lock()
myCharacter.STR = mySTR
myCharacter.DEX = myDEX
mutex.Unlock()
还有:
mutex.Lock()
fmt.Printf("STR: %d DEX: %d", myCharacter.STR, myCharacter.DEX)
mutex.Unlock()
没有互斥量,就无法保证对共享变量所做的修改对其他 goroutine 可见。
你的 goroutines 永远不会 运行。 main 不等待 goroutines 完成,它在执行之前打印并退出。
这可以通过 WaitGroups 来解决,让 main 等待所有 goroutine 完成。它基本上是一个花哨的计数器。
// Create the WaitGroup
var wg sync.WaitGroup
// Add one thing to wait for.
// This must be done outside the goroutine to ensure it's added
// before `wg.Wait()` is called.
wg.Add(1)
go func() {
# When the goroutine exits, say this one thing is done.
defer wg.Done()
for {
...
}
}()
// Same for the next one.
wg.Add(1)
go func() {
defer wg.Done()
for {
...
}
}()
// Wait until the two things in the WaitGroup are done.
wg.Wait()
fmt.Printf("STR: %d DEX: %d", myCharacter.STR, myCharacter.DEX)
这会让你的 goroutines 运行ning。接下来是不剪切&粘贴代码,而是使用循环。
for i:= 0; i < 2; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
myCharacter.STR = 42;
myCharacter.DEX = 23;
break;
}
}()
}
请注意,如果您希望两个值均为 1,000,000,则需要尝试 1,000,000,000,000 次(1 万亿)。两个 goroutines 不会使那么快。
所以,我是 Go 的新手,上周末开始学习这门语言,并为 RPG 创建了一个基本的字符生成器/自动滚动器。 由于生成器会进行大量随机数滚动,直到达到某些值,我想我可能会使用 goroutines 来加快处理速度。 到目前为止,这是我最大的努力,但不知何故,在最终的 Printf 期间,我总是得到“STR: 0 DEX: 0”,即使我在调试期间可以看到两个并行函数正在正确设置值。 myCharacter 结构是在它们之外声明的,所以我认为更新它应该可以正常工作?
这是我糟糕的代码。我想要实现的是在并行 goroutine 中滚动“STR”和“DEX”,直到其中一个达到任意条件(这里的值都是 1000000,只是作为测试)。
任何人都可以帮我解决为什么 myCharacter.STR 和 myCharacter.DEX 最后打印为 0?
package main
import (
"fmt"
"math/rand"
"time"
)
type Character struct {
STR int
DEX int
}
func main() {
rand.Seed(time.Now().UTC().UnixNano())
QuitChan := make(chan bool)
myCharacter := new(Character)
go func() {
for {
select {
case <-QuitChan:
return
default:
mySTR, myDEX := RollChar()
if mySTR >= 1000000 && myDEX >= 1000000 {
myCharacter.STR = mySTR
myCharacter.DEX = myDEX
QuitChan <- true
return
}
}
}
}()
go func() {
for {
select {
case <-QuitChan:
return
default:
mySTR, myDEX := RollChar()
if mySTR >= 1000000 && myDEX >= 1000000 {
myCharacter.STR = mySTR
myCharacter.DEX = myDEX
QuitChan <- true
return
}
}
}
}()
fmt.Printf("STR: %d DEX: %d", myCharacter.STR, myCharacter.DEX)
}
func RollChar() (int, int) {
mySTR := rand.Intn(1000000) + 1
myDEX := rand.Intn(1000000) + 1
return mySTR, myDEX
}
您有一场数据竞赛。您的两个 goroutines 正在访问共享变量而没有任何显式同步。在这种情况下,您需要使用互斥锁来确保互斥以及在一个 goroutine 中所做的更改在其他 goroutine 中的可见性。
声明一个互斥量:
myCharacter := new(Character)
mutex:=sync.Mutex{}
在 read/write 共享变量时使用互斥体:
mutex.Lock()
myCharacter.STR = mySTR
myCharacter.DEX = myDEX
mutex.Unlock()
还有:
mutex.Lock()
fmt.Printf("STR: %d DEX: %d", myCharacter.STR, myCharacter.DEX)
mutex.Unlock()
没有互斥量,就无法保证对共享变量所做的修改对其他 goroutine 可见。
你的 goroutines 永远不会 运行。 main 不等待 goroutines 完成,它在执行之前打印并退出。
这可以通过 WaitGroups 来解决,让 main 等待所有 goroutine 完成。它基本上是一个花哨的计数器。
// Create the WaitGroup
var wg sync.WaitGroup
// Add one thing to wait for.
// This must be done outside the goroutine to ensure it's added
// before `wg.Wait()` is called.
wg.Add(1)
go func() {
# When the goroutine exits, say this one thing is done.
defer wg.Done()
for {
...
}
}()
// Same for the next one.
wg.Add(1)
go func() {
defer wg.Done()
for {
...
}
}()
// Wait until the two things in the WaitGroup are done.
wg.Wait()
fmt.Printf("STR: %d DEX: %d", myCharacter.STR, myCharacter.DEX)
这会让你的 goroutines 运行ning。接下来是不剪切&粘贴代码,而是使用循环。
for i:= 0; i < 2; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
myCharacter.STR = 42;
myCharacter.DEX = 23;
break;
}
}()
}
请注意,如果您希望两个值均为 1,000,000,则需要尝试 1,000,000,000,000 次(1 万亿)。两个 goroutines 不会使那么快。