在单个函数中使用多个上下文:重用和取消

huangapple go评论72阅读模式
英文:

Multiple contexts in a single function: reuse, and cancellation

问题

在一个函数中执行了几个使用各自上下文的任务。如果上下文没有超时,就会显式调用取消函数。类似这样:

ctx, cancel := contextWithTimeout(...)
defer cancel()

doSomethingA(ctx, ...)
// 验证 doSomethingA 没有错误
cancel()

ctx, cancel = contextWithTimeout(...)
defer cancel()

doSomethingB(ctx, ...)
// 验证 doSomethingB 没有错误
cancel()

变量名(ctxcancel)被重复使用,并且每次都手动调用 cancel() 函数,而不是等待 defer。

这种处理多个上下文的方式是否合适?

英文:

There are a few tasks performed in a function that all use their own contexts. The cancel functions are being explicitly called if the context does not time out. Something like this:

ctx, cancel := contextWithTimeout(...)
defer cancel()

doSomethingA(ctx, ...)
// verify no errors from doSomethingA
cancel()

ctx, cancel = contextWithTimeout(...)
defer cancel()

doSomethingB(ctx, ...)
// verify no errors from doSomethingB
cancel()

The names (ctx, cancel) are being reused, and the cancel() function is being manually called every time instead of waiting for the defer.

Is this an appropriate way to handle multiple contexts?

答案1

得分: 1

在这种情况下,你可能会发现一种有用的模式是将代码块包装在不同的闭包中。这样做的主要优点是,你可以使用defer来调用cancel(),如果有很多分支需要显式调用cancel(),那么这种方式可能更可取。

根据你的偏好,你可以在闭包内部或外部处理任何返回的错误。

func() {
  ctx, cancel := contextWithTimeout(...)
  defer cancel()

  err := doSomethingA(ctx, ...)
  if err != nil {
    // 处理错误。
  }
}()

err := func() error {
  ctx, cancel := contextWithTimeout(...)
  defer cancel()

  return doSomethingB(ctx, ...)
}()
// 在这里处理doSomethingB的错误。

这种模式对于需要关闭以避免泄漏的资源也很有用,比如HTTP响应体、文件和网络连接。

英文:

A pattern you might find useful in this case is to wrap the blocks of your code into different closures. The main advantage of doing this is that you can use defer to call cancel() which might be preferable if there are a lot of branches where you would otherwise have to call cancel() explicitly.

Depending on your preference you can deal with any returned errors outside or inside the closure

func() {
  ctx, cancel := contextWithTimeout(...)
  defer cancel()

  err := doSomethingA(ctx, ...)
  if err != nil {
    // handle error.
  }
}()

err := func() error {
  ctx, cancel := contextWithTimeout(...)
  defer cancel()

  return doSomethingB(ctx, ...)
}()
// Handle error of doSomethingB here.

This pattern is also useful for resources which need to be closed to avoid leaks like http response bodies, files and network connections.

huangapple
  • 本文由 发表于 2021年11月29日 10:05:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/70149073.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定