【问题标题】:generate context.Context from Done channel & GC of unclosed channels从完成通道和未关闭通道的 GC 生成 context.Context
【发布时间】:2023-09-06 21:23:01
【问题描述】:

背景:

我正在利用自定义 LDAP 服务器package。它在请求中使用Done 通道让处理程序知道是否 - 比如说客户端断开连接 - 因此处理程序也应该中止。 For example.

由于 Done 频道是处理取消的旧方式 - 并且我希望支持取消链接 - 我从这个频道创建了一个 context.Context,如下所示:

func doneContext(p context.Context, done <-chan bool) (
    ctx context.Context, cancel context.CancelFunc,
) {
    ctx, cancel = context.WithCancel(p)
    go func() {
            <-done
            cancel() // done closed, so cancel our context
    }()
    return
}

这假设done 通道将被关闭:

  • 客户端断开连接;
  • 成功的处理程序(完全运行到完成)

第一个证明是正确的 - 第二个没有。成功的处理程序调用不会触发 done 通道关闭 - 因此我正在泄漏 go-routines。


为了解决这个问题 - 因为我在处理程序完成时取消了我自己的 context.Context - 成功与否,例如

// convert the client request's Done channel into a context.Context
ctx, cancel := doneContext(context.Background(), m.Done)
defer cancel() // clean-up context: rain or shine

我像这样更新了doneContext 的 goroutine:

go func() {
        select {
        case <-done:
            cancel() // done closed, so cancel our context (like before)

        case <-ctx.Done():
            // when our context is canceled, recover the go-routine (even if done never closes)
        }
}()

问题:

  • 这是将旧式done 频道升级为更现代context.Context 的正确方法吗?
  • 我应该担心我使用的外部包没有关闭done 频道吗?
    • GC 会收集这个频道,即使它从未关闭过?

【问题讨论】:

  • 关闭通道不是清理操作,也不需要关闭它们。 channel close spec 列出了有关操作的所有详细信息。
  • 明白。然而,规范链接没有明确提到 GC - 所以我猜它的遗漏不是 GC 要求。
  • 是的,规范(以及一般的 Go 文档)无法列出您不必必须做的所有可能的事情。文档非常好,因此您可以先假设语言是精确的。

标签: go garbage-collection cancellation


【解决方案1】:

您无需关闭频道。如果没有任何东西引用通道,它将被垃圾回收。

您的频道逻辑显示正确。

【讨论】: