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