Search code examples
gogoroutine

About the behavior of go routine in go routine


I'm newie to golang and studying the goroutine.
I wrote the simple code that divide the number using goroutine on purpose.
First of all, I give the base number and keep on dividing its number until it is not divisible
But, I change go split(n) to split(n), it is not working like the following, is this why?

■ source code

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
    "os"
    "strconv"
)

var next = make(chan int)
var quit = make(chan int)

func divide(n int) {
    defer func(){ quit <- 1 }()

    fmt.Println("[divide] n = " + strconv.Itoa(n))

    r := n % 2
    if r == 0 {
        next <- n / 2
    }
}

func execute() {

    fmt.Println("[execute] start")
    count := 0
    end   := false
    for !end {
        select {
        case n := <- next:
            count++
            fmt.Println("[execute] n = " + strconv.Itoa(n) + ", count = " + strconv.Itoa(count))
            go divide(n)
        case _ = <- quit:
            count--
            fmt.Println("[execute] end. count = " + strconv.Itoa(count))
            if count <= 0 {
                end = true
            }
        }
    }
    fmt.Println("complete")
    os.Exit(0)
}

func main() {

    base := flag.Int("n", 1, "Input the number")
    flag.Parse()

    if *base <= 0 {
        fmt.Println("please more than 1")
        os.Exit(0)
    }

    go execute()
    next <- *base

    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal("ListenAndSearver:", err)
    }
}

■ result(work fine)

$ go run main.go -n 6
[execute] start
[execute] n = 6, count = 1
[divide] n = 6
[execute] n = 3, count = 2
[execute] end. count = 1
[divide] n = 3
[execute] end. count = 0
complete

■ result(not work)

$ go run main.go -n 6
[execute] start
[execute] n = 6, count = 1
[divide] n = 6


Solution

  • Without go divide() inside execute:

    • execute() reads from the next channel, calls divide
    • divide() waits to write to next
    • execute() is still waiting for divide() to return, so program is now deadlocked.

    With go divide() inside execute:

    • execute() reads from the next channel, starts divide in new goroutine, continues waiting
    • divide() writes to next
    • execute() reads from next, starts another goroutine, etc.

    Note that as soon as divide writes to next, it continues to write to quit so you may receive multiple quit messages before everything is done.