当上下文变量超出范围并且未明确调用cancel时,context.Done()是否会解锁?
我们说我有以下代码:
func DoStuff() {
ctx, _ := context.WithCancel(context.Background())
go DoWork(ctx)
return
}
在DoStuff()中返回后,ctx.Done()会在DoWork中解锁吗?
我找到了这个帖子https://groups.google.com/forum/#!topic/golang-nuts/BbvTlaQwhjw,其中询问如何使用Context.Done()的人声称context.Done()会在上下文变量离开范围时解锁,但没有人验证这个,我没有& #39;在文档中看到任何内容。
答案 0 :(得分:6)
不,当上下文离开范围时,它不会自动取消。通常一个人调用defer cancel()
(使用ctx.WithCancel()
的回调)来确保上下文被取消。
https://blog.golang.org/context概述了如何正确使用上下文(包括上面的defer
模式)。此外,源代码https://golang.org/src/context/context.go非常易读,您可以看到没有可以自动取消的魔法。
答案 1 :(得分:2)
"解锁"不是最清楚的术语。 Done()
返回一个频道(或零),当上下文被取消时,它将收到struct{}
和/或关闭"。这个chan究竟是什么,或者什么时候发送,取决于个人实现。与WithDeadline
一样,可以在某个固定时间发送/关闭,也可以像WithCancel
一样手动完成。
关键是,这绝不是"自动"或保证会发生。如果您使用WithCancel
创建上下文并从Done()
频道中读取,则该读取将阻止无限期,直到调用Cancel()
方法为止。如果这种情况从未发生过,那么你就会浪费goroutine,每次执行时你的应用程序内存都会增加。
一旦上下文完全超出范围(没有正在执行的goroutine正在侦听它或者有对父上下文的引用),它将被垃圾收集并且一切都会消失。
编辑:在阅读完源代码后,它看起来像WithCancel,并且朋友会产生goroutines以提示取消。因此,必须确保在某个时刻调用Cancel以避免goroutine泄漏。