当上下文变量超出golang的范围时,Context.Done()是否会解锁?

时间:2017-05-08 17:56:09

标签: go

当上下文变量超出范围并且未明确调用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;在文档中看到任何内容。

2 个答案:

答案 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泄漏。