等待 goroutine 完成的正确方法
Posted
技术标签:
【中文标题】等待 goroutine 完成的正确方法【英文标题】:proper way of waiting for a go routine to finish 【发布时间】:2014-11-15 06:17:41 【问题描述】:我想知道在退出程序之前是什么。阅读其他一些答案,bool chan 似乎可以解决问题,如Playground link
func do_stuff(done chan bool)
fmt.Println("Doing stuff")
done <- true
func main()
fmt.Println("Main")
done := make(chan bool)
go do_stuff(done)
<-done
//<-done
我有两个问题:
为什么
如果我取消最后一行的注释会发生什么?我有一个死锁错误。这是因为通道是空的,没有其他函数向它发送值吗?
【问题讨论】:
<- done
有效,因为这正是频道所做的 :)(有关详细信息,请参阅 golang.org/ref/spec#Receive_operator 和 golang.org/ref/spec#Send_statements)。关于取消注释第二行如何导致僵局,您是对的。没有任何东西发送到 done
并且 Go 认识到,如果它等待,甚至没有任何东西 可以(例如,没有任何东西在等待网络调用)。
【参考方案1】:
为什么<- done
完全有效?
如果我取消最后一行的注释会怎样?
运行时足够聪明,可以知道没有任何其他内容正在写入并且它会死锁。奖励,如果你的内存非常有限,你可以使用done := make(chan struct)
和done <- struct
,struct
保证使用 0 内存。
【讨论】:
你错过了否定吗? “足够聪明”+“死锁”——我认为如果它很聪明,它就不会死锁,而是会给你一个错误,说它会死锁。所以在我看来,要么运行时不够聪明,要么它没有死锁。是哪个? 它足够聪明,因为它会给你一个错误,告诉你它已经死锁了。【参考方案2】:收听频道<- done
,是一个阻塞操作,所以你的程序将不会继续,直到发送真或假,即done <- true
。
根据具体情况,您的问题可能会有不同的答案。
例如,假设您想要并行化一系列需要很长时间的函数调用。
我会为此使用 sync
包
package main
import (
"fmt"
"sync"
"time"
)
func main()
var wg sync.WaitGroup
for i := 0; i < 10; i++
wg.Add(1)
go func()
longOp()
wg.Done()
()
// will wait until wg.Done is called 10 times
// since we made wg.Add(1) call 10 times
wg.Wait()
func longOp()
time.Sleep(time.Second * 2)
fmt.Println("long op done")
【讨论】:
以上是关于等待 goroutine 完成的正确方法的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 time.Sleep 的情况下等待所有 goroutines 完成?