ctx.Err() 与 ctx.Done() chan 关闭检查:有区别吗?

Ahm*_*gle 9 go

我处于一个长时间运行的可取消函数中,该函数具有永远循环。

我需要检查上下文是否已关闭。

go func(){
    for {
         if ctx.Err() != nil { return }
         // do work
    }
}()
Run Code Online (Sandbox Code Playgroud)

go func(){
    for {
         select {
            case <-ctx.Done():
                return
            default:
         }
         // do work
    }
}()
Run Code Online (Sandbox Code Playgroud)

两者有区别吗?

我猜测检查 ctx.Err() 对于并发访问是安全的https://golang.org/src/context/context.go#L370所以它们看起来是相同的,给定一个封闭的上下文将始终设置 Err。

Hym*_*sco 12

context.Context 文档中:

如果 Done 尚未关闭,Err 返回 nil。如果 Done 关闭,Err 返回一个非零错误并解释原因

通过扩展,我们可以说您的第一个示例正在检查是否Done已关闭。鉴于已完成通道的约定,它们应该只被关闭,并且永远不会向它们发送任何值,我们可以说您的第二个示例也在检查是否已Done关闭。

因此,我们可以说这两个代码示例在功能上是等效的。我们之所以采用不同的检查方法是因为每种方法都有一些好处:

  • Err()是立即检查并给出错误信息。
  • Done()是一个通道,因此可以在案例中等待或使用select