为了账号安全,请及时绑定邮箱和手机立即绑定

在 Golang 中使用上下文超时停止运行函数

在 Golang 中使用上下文超时停止运行函数

Go
Helenr 2022-05-23 17:36:46
我想利用 golang 中的上下文在超时时用于取消。编码:package mainimport "fmt"import "time"import "context"func F(ctx context.Context) error {  ctx, cancel := context.WithTimeout(ctx,3*time.Second)  defer cancel()  for i:=0;i<10;i++ {    time.Sleep(1 * time.Second)    fmt.Println("No: ",i)  }  select {    case <-ctx.Done():      fmt.Println("TIME OUT")      cancel()      return ctx.Err()    default:      fmt.Println("ALL DONE")      return nil  }}func main() {  ctx := context.Background()  err := F(ctx)  if err != nil {    fmt.Println(err)  }else {    fmt.Println("Success")  }}期望:上面的代码应该在 counter 停止运行循环2,因为超时是 3 秒,循环运行 1 秒。所以我期待这样的事情:No:  0No:  1No:  2TIME OUTcontext deadline exceeded实际:实际发生的情况是循环继续运行直到完成,即使上下文遇到超时并且选择侦听器在<-ctx.Done(). 此代码打印:No:  0No:  1No:  2No:  3No:  4No:  5No:  6No:  7No:  8No:  9TIME OUTcontext deadline exceeded超时满足后如何停止函数执行?
查看完整描述

1 回答

?
红糖糍粑

TA贡献1815条经验 获得超6个赞

context.Context只能中继发生超时或取消的消息。它无权实际停止任何 goroutines(有关详细信息,请参阅取消 Go 中的阻塞操作)。goroutine 本身负责检查超时和取消,并提前中止。


你有一个循环,它无条件地迭代 10 次并打印一些东西。而且您只在循环后检查超时。


您必须将上下文检查移动到循环中:


func F(ctx context.Context) error {

    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)

    defer cancel()

    for i := 0; i < 10; i++ {

        select {

        case <-ctx.Done():

            fmt.Println("TIME OUT")

            return ctx.Err()

        default:

            time.Sleep(1 * time.Second)

            fmt.Println("No: ", i)

        }

    }

    fmt.Println("ALL DONE")

    return nil

}

通过此更改,输出将是(在Go Playground上尝试):


No:  0

No:  1

No:  2

No:  3

TIME OUT

context deadline exceeded

注意:无论您看到"No: 3"打印可能会或可能不会发生,因为任何迭代都需要 1 秒,并且超时是 3 秒 = 3 * 迭代延迟,所以是先发生超时还是第 4 次迭代首先开始是“活泼的”。如果将超时时间减少到 2900 毫秒,"No: 3"则不会打印。


查看完整回答
反对 回复 2022-05-23
  • 1 回答
  • 0 关注
  • 637 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号