I started to learn go language days ago. When I tried to start writing some fun codes, I am stuck by a strange behavior.
package main
import "fmt"
func recv(value int) {
if value < 0 {
return
}
fmt.Println(value)
go recv(value-1)
}
func main() {
recv(10)
}
when I run the above code, only 10
is printed. When I remove the go
before the call to recv
, 10
to 0
are printed out. I believe I am misusing go routine here, but I can not understand why it failed start a go routine this way.
When the main function returns, Go will not wait for any still existing goroutines to finish but instead just exit.
recv
will return to main after the first "iteration" and because main has nothing more to do, the program will terminate.
One solution to this problem is to have a channel that signals that all work is done, like the following:
package main
import "fmt"
func recv(value int, ch chan bool) {
if value < 0 {
ch <- true
return
}
fmt.Println(value)
go recv(value - 1, ch)
}
func main() {
ch := make(chan bool)
recv(10, ch)
<-ch
}
Here, recv
will send a single boolean before returning, and main
will wait for that message on the channel.
For the logic of the program, it does not matter what type or specific value you use. bool
and true
are just a straightforward example. If you want to be more efficient, using a chan struct{}
instead of a chan bool
will save you an additional byte, since empty structs do not use any memory.
A sync.Waitgroup
is another solution and specifically intended for the purpose of waiting for an arbitrary amount of goroutines to run their course.
package main
import (
"fmt"
"sync"
)
func recv(value int, wg *sync.WaitGroup) {
if value < 0 {
return
}
fmt.Println(value)
wg.Add(1) // Add 1 goroutine to the waitgroup.
go func() {
recv(value-1, wg)
wg.Done() // This goroutine is finished.
}()
}
func main() {
var wg sync.WaitGroup
recv(10, &wg)
// Block until the waitgroup signals
// all goroutines to be finished.
wg.Wait()
}
I did so and also worked. How come?
package main
import "fmt"
func recv(value int) {
if value < 0 {
return
}
fmt.Println(value)
recv(value - 1)
}
func main() {
recv(10)
}