1.简介

goroutinegoroutinegoroutinegoroutine

2.为什么需要关闭goroutine

2.1 协程的生命周期

goroutine
Go

首先需要创建一个协程,协程的创建可以通过关键字 go 来实现,例如:

上面的代码会启动一个新的协程,同时在新的协程中执行匿名函数,此时协程便已被创建了。

P

在运行阶段,协程会不断地执行任务,直到任务完成或者遇到终止条件。在终止阶段,协程将会被回收,从而完成其整个生命周期。

go

2.2 协程的终止条件

正常来说,都是协程任务执行完成之后,此时协程自动退出,例如:

WaitGroup

还有一种情况是协程发生panic,它将会自动退出。例如:

在这种情况下,协程也会自动退出,不会再占用系统资源。

综合看来,协程的终止条件,其实就是协程中的任务执行完成了,或者是执行过程中发生了panic,协程将满足终止条件,退出执行。

2.3 为什么需要主动关闭goroutine

goroutine
channelchannelchannel
goroutinechannelchannel

但是,假如生产者出现了问题,此时生产者的协程将会被退出,不再执行。而消费者仍然在等待数据的输入。此时消费者协程已经没有存在的必要了,其实是需要退出执行。

因此,对于一些虽然没有达到终止条件的协程,但是其又没有再继续执行下去的必要,此时主动关闭其执行,从而保证程序的健壮性和性能。

3.如何优雅得关闭goroutine

goroutinegoroutine

3.1 传递关闭终止信号

goroutinecontext.ContextWithCancelWithDeadlineWithTimeoutContextCancelContext
contextCancelcontext

3.2 协程内部捕捉终止信号

selectselectcasechannelselectcaseselect
contextDonechannelchannelselectcasedefault

3.3 回收协程资源

defer
defer

3.4 关闭goroutine示例

Contextselectdefer
maincontext.WithCancelcontextworkerworker
workercancelworkerworkerselect
defer

4. 需要主动关闭协程运行的常见场景

4.1 协程在执行一个不断重复的任务

goroutine
etcdetcdetcd
etcd
etcdetcdLeaseGrantPut
etcd
etcdLease
LeaseKeepAliveKeepAlive
LeaseCloseLeaseLeaseKeepAlive
etcdLeaseKeepAlivecontextselectdefer

下面来看看执行续约操作的函数,会启动一个协程在后台不断执行,具体实现如下:

tosendetcdetcd
stopCtxlessorlessorstopCtxcontext.WithCancel()context.ContextstopCtxstopCancel
lessor.Close()stopCancel()
sendKeepAliveLoop()stopCtxstopCancel()stopCtxlessorstopCtx

5.总结

goroutinegoroutine
goroutineGogoroutinecontextselectdefer
goroutine