So, I'm very new to Go, started learning the language last weekend and created a basic character generator / autoroller for an RPG. Since the generator does a lot of random number rolling until certain values are reached, I thought I might use goroutines to speed up processing. This is my best effort so far but somehow during the final Printf I always get "STR: 0 DEX: 0" even though I can see during debugging that the two parallel functions are setting the values correctly. The myCharacter struct is declared outside of them so I thought updating it should work fine?
This is my awful code. What I'm trying to achieve is roll for "STR" and "DEX" in parallel goroutines until one of them reaches an arbitrary condition (here a value of 1000000 for both just as a test).
Anybody can help me out why myCharacter.STR and myCharacter.DEX print out as 0 at the end?
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
}
Your goroutines never run. main does not wait for goroutines to complete, it prints and quits before they execute.
This can be solved with WaitGroups to make main wait until all goroutines are done. Its basically a fancy counter.
// 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)
That will get your goroutines running. Next is to not cut & paste the code, and use a loop.
for i:= 0; i < 2; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
myCharacter.STR = 42;
myCharacter.DEX = 23;
break;
}
}()
}
Note that if you expect both values to be 1,000,000 that will take 1,000,000,000,000 tries (1 trillion). Two goroutines will not make that much faster.