我几天前开始学习语言。当我试着开始写一些有趣的代码时,我被一种奇怪的行为所困扰。
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
之前删除recv
,则会打印10
至0
。我相信我在这里滥用常规,但我无法理解为什么它以这种方式开始一个例行程序失败。
答案 0 :(得分: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
只是一个简单的例子。如果您想提高效率,使用chan struct{}
代替chan bool
将为您节省额外的字节,因为空结构不使用任何内存。
答案 1 :(得分:10)
sync.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()
}
答案 2 :(得分:-2)
我这样做也工作过。怎么样?
package main
import "fmt"
func recv(value int) {
if value < 0 {
return
}
fmt.Println(value)
recv(value - 1)
}
func main() {
recv(10)
}