关于go routine在go routine中的行为

About the behavior of go routine in go routine

我是 golang 的新手,正在研究 goroutine。
我特意用 goroutine 写了简单的除数代码。
首先,我给出底数,不断除以它的数,直到不可整除
但是,我将 go split(n) 更改为 split(n),它并没有像下面这样工作,这是为什么?

■ 源代码

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)
    }
}

■ 结果(工作正常)

$ 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

■ 结果(无效)

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

没有 go divide() 内部执行:

  • execute() 从 next 通道读取,调用 divide
  • divide() 等待写入 next
  • execute() 仍在等待 divide() 到 return,所以程序现在死锁了。

go divide()里面执行:

  • execute() 从 next 通道读取,在新的 goroutine 中启动 divide,继续等待
  • divide() 写入 next
  • execute() 从 next 读取,启动另一个 goroutine,等等

请注意,一旦 divide 写入 next,它就会继续写入 quit,因此您可能会在一切完成之前收到多条退出消息。