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.
The Go programming language supports recursion. That is, it allows a function to call itself. But while using recursion, programmers need to be careful to define an exit condition from the function, otherwise it will go on to become an infinite loop.
Go accepts recursion functions. A function is recursive if it calls itself and reaches a stop condition. In the following example, testcount() is a function that calls itself. We use the x variable as the data, which increments with 1 ( x + 1 ) every time we recurse.
Recursion is a process of calling itself. A function that calls itself is called a recursive function. The syntax for recursive function is: function recurse() { // function code recurse(); // function code } recurse(); Here, the recurse() function is a recursive function.
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()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With