【问题标题】:Does Context.Done() unblock when context variable goes out of scope in golang?当上下文变量超出 golang 的范围时,Context.Done() 是否会解除阻塞?
【发布时间】:2017-05-09 02:26:42
【问题描述】:

当上下文变量超出范围并且没有显式调用取消时,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() 将在上下文变量离开范围但没有人验证时解除阻塞,而我没有在文档中查看任何内容。

【问题讨论】:

  • 我认为您认为提出此建议的人只是在询问它是否会自动取消而不是声明任何内容。

标签: go


【解决方案1】:

不,当上下文离开范围时它不会自动取消。通常会自己调用defer cancel()(使用来自ctx.WithCancel() 的回调)以确保上下文被取消。

https://blog.golang.org/context 很好地概述了如何正确使用上下文(包括上面的defer 模式)。另外,https://golang.org/src/context/context.go 的源代码可读性很强,你可以看到没有魔法可以提供自动取消。

【讨论】:

    【解决方案2】:

    “解锁”不是最清晰的术语。 Done() 返回一个通道(或 nil),该通道将接收 struct{} 和/或在上下文“取消”时关闭。 chan 究竟是什么,或者何时发送,取决于个人的实现。它可以像WithDeadline 一样在某个固定时间发送/关闭,或者像WithCancel 一样手动完成。

    不过,关键是这永远不会“自动”或保证会发生。如果您使用WithCancel 创建上下文并从Done() 通道读取,则该读取将无限期 阻塞,直到调用Cancel() 方法。如果这种情况永远不会发生,那么您就浪费了一个 goroutine,并且每次执行此操作时应用程序的内存都会增加。

    一旦上下文完全超出范围(没有正在执行的 goroutine 正在监听它或没有对父上下文的引用),它将被垃圾收集并且一切都会消失。

    编辑:不过,在阅读了源代码后,它看起来像 WithCancel 和朋友们产生了 goroutines 来传播取消。因此,您必须确保在某个时候调用 Cancel 以避免 goroutine 泄漏。

    【讨论】:

      猜你喜欢
      • 2012-12-03
      • 2018-10-05
      • 2016-05-12
      • 2019-05-09
      • 1970-01-01
      • 2016-04-30
      • 1970-01-01
      相关资源
      最近更新 更多