从 vert 那里得到了这个:



代码如下:

func foo(ctx context.Context) {
  for ... some loop {
    c, _ := context.WithTimeout(ctx, time.Second)
    err = enc.RequestWithContext(c, "some", someRequest, &response)
    if err != nil {
      continue
    }
    if response.Code == -1 {
      break
    }
  }
}

那么在请求后在这里取消它有什么意义呢?只是为了使vet开心?无论如何,该上下文已经结束或超时。

func foo(ctx context.Context) {
  for ... some loop {
    c, cancel := context.WithTimeout(ctx, time.Second)
    err = enc.RequestWithContext(c, "some", someRequest, &response)
    cancel()

    if err != nil {
      continue
    }
    if response.Code == -1 {
      break
    }
  }
}

最佳答案

c, cancel := context.WithTimeout(ctx, time.Second)
err = enc.RequestWithContext(c, "some", someRequest, &response)
cancel()
enc.RequestWithContext()可能会在1秒超时之前正常返回,并且仅当您调用cancel()时,上下文所使用的资源才会立即释放。
cancel()是幂等的,您可以在多个goroutine中同时调用它多次。随后的通话是noop。如果上下文已经超时或已调用cancel()(再次)调用,则无害。

确定调用被取消是最简单的方法,例如defer:
c, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
err = enc.RequestWithContext(c, "some", someRequest, &response)

但是,当此代码段在循环内时要小心:仅在周围函数结束时才执行延迟函数,而在下一个循环迭代开始时才执行。在这种情况下,应使用函数文字或命名函数来确保在下一次迭代开始之前执行了延迟的调用。有关详细信息,请参见`defer` in the loop - what will be better?

一个可能的解决方案是:
for ... some loop {
    res := func() bool {
        c, cancel := context.WithTimeout(ctx, time.Second)
        defer cancel()
        err = enc.RequestWithContext(c, "some", someRequest, &response)
        if err != nil {
            return false
        }
        if response.Code == -1 {
            return true
        }
    }()
    if res {
        break
    }
}

关于go - 对于上下文而言,取消如此强制吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59858033/

10-16 09:26