12

几天前我开始学习 Go 语言。当我试图开始编写一些有趣的代码时,我被一种奇怪的行为所困扰。

package main

import "fmt"

func recv(value int) {
    if value < 0 {
        return
    }

    fmt.Println(value)
    go recv(value-1)
}

func main() {
    recv(10)
}

当我运行上面的代码时,只10打印出来。当我go在调用 to 之前删除torecv时,会打印出来。我相信我在这里滥用了 goroutine,但我不明白为什么它无法以这种方式启动 goroutine。100

4

3 回答 3

16

当 main 函数返回时,Go 不会等待任何仍然存在的 goroutine 完成,而是直接退出。

recv将在第一次“迭代”后返回 main 并且因为 main 没有更多事情要做,程序将终止。

解决此问题的一种方法是使用一个通道来指示所有工作已完成,如下所示:

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
}

在这里,recv将在返回之前发送一个布尔值,并main在通道上等待该消息。

对于程序的逻辑,你使用什么类型或具体值并不重要。bool并且true只是一个简单的例子。如果您想提高效率,使用 achan struct{}而不是 achan bool将为您节省一个额外的字节,因为空结构不使用任何内存。

于 2012-11-12T04:19:27.413 回答
10

Async.Waitgroup是另一种解决方案,专门用于等待任意数量的 goroutine 运行它们的过程。

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()
}
于 2012-11-13T11:21:12.357 回答
-2

我这样做了,也工作了。怎么会?

package main

import "fmt"

func recv(value int) {
    if value < 0 {
      return
    }

    fmt.Println(value)
    recv(value - 1)
}

func main() {
  recv(10)
}
于 2014-12-23T17:33:37.770 回答