Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

golang recursive function calling itself as a goroutine doesn't work as expected [duplicate]

This recursive function works as expected (returns 5 lines with numbers 5 to 1):

package main
import (
    "fmt"
)
func recur(iter int) {
    if iter <= 0 {
        return
    }
    fmt.Println(iter)
    recur(iter-1)
}
func main() {
    recur(5)
}

this one does not (returns only 1 line with number 5):

    package main
import (
    "fmt"
)
func recur(iter int) {
    if iter <= 0 {
        return
    }
    fmt.Println(iter)
    go recur(iter-1)
}
func main() {
    recur(5)
}

The difference is that in the second implementation, function calls itself as a goroutine. (line go recur(iter-1) )

So can someone explain this behaviour?

like image 335
RSH Avatar asked Sep 18 '16 04:09

RSH


2 Answers

If you make everything asynchronous, there is nothing in main to wait on. You have to explicitly wait on the go routines so your program does not exit before the recursive process finishes.

Use sync.WaitGroup or something similar for synchronization. Example (On Play):

func recur(iter int, g *sync.WaitGroup) {
    defer g.Done()
    if iter <= 0 {
        return
    }
    fmt.Println(iter)
    go recur(iter-1, g)
}

func main() {
    g := &sync.WaitGroup{}
    runs := 5
    g.Add(runs)
    recur(runs, g)
    g.Wait()
}
like image 126
nemo Avatar answered Nov 15 '22 09:11

nemo


Your programming is exiting before all the goroutines finish. The simplest way to see this work is as follows.

package main

import (
    "fmt"
    "time"
)

func recur(iter int) {
    if iter <= 0 {
        return
    }
    fmt.Println(iter)
    go recur(iter - 1)
}
func main() {
    recur(5)
    time.Sleep(time.Second)
}

playground link

Rather than sleeping, however, you may want to pass a sync.WaitGroup through to your function.

like image 28
Amit Kumar Gupta Avatar answered Nov 15 '22 09:11

Amit Kumar Gupta