go 优雅的结束goroutine
对于通知一个goroutine结束它的工作,遵循goroutine之间通过管道传递消息的设计理念,我们可以使用channel传递一个信号,当goroutine检测到信号,结束工作即可:
var wg sync.WaitGroup
func work(exit <-chan struct{}) {
LABEL:
for {
select {
case <-exit:
break LABEL
default:
fmt.Println("working...")
time.Sleep(time.Second * 1)
}
}
wg.Done()
}
func main() {
exit := make(chan struct{})
wg.Add(1)
go work(exit)
time.Sleep(time.Second * 5)
exit <- struct{}{}
wg.Wait()
}
其实go语言本身的context包已经实现了这样的机制,用来处理goroutine之间切换上下文,在多个goroutine之间传递消息,也可以实现优雅关闭的效果:
func work2(ctx context.Context, cancel context.CancelFunc) {
LABEL:
for {
select {
case <-ctx.Done():
break LABEL
default:
fmt.Println("working...")
time.Sleep(time.Second * 1)
}
}
wg.Done()
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
wg.Add(1)
go work2(ctx, cancel)
time.Sleep(time.Second * 5)
cancel()
wg.Wait()
}
除了withCancel,还有withTimeout、withDeadline、withValue方式来创建context,具体使用比较简单不再介绍