繁体   English   中英

如何使用 Go 的 WithTimeout 检测超时

[英]How to detect a timeout occurred using Go's WithTimeout

我有以下 Go 代码:

func MyFunc(ctx context.Context, cfg *Config) (packedevent []byte, err error, publishEvent bool) {
    var cancel context.CancelFunc
    ctx, cancel = context.WithTimeout(ctx, cfg.ScanTimeout)
    defer cancel()

    event := GetEvent(ctx, cfg)
    packedevent, err = PackEvent(event)

    publishEvent = shouldSendToIoT(event)

    return
}

我试图使用context.WithTimeout使这个 function 超时。

我无法弄清楚的是如果发生超时如何设置err

我查看了 Go 文档中的示例,但我并没有真正理解它。 <-ctx.Done()情况是否总是意味着已达到超时? 这个例子似乎暗示了相反的情况—— <-ctx.Done()意味着代码在没有超时的情况下运行完成。

我正在寻找有关如何检测使用context.WithTimeout运行的代码何时超时或未超时的说明。

此外,我想了解我应该在我的代码中的哪个位置检查超时是否发生。 我的第一个想法是将这张支票放在 function 的末尾,但这样会不会太晚了?

要检测上下文是否超时,请检查ctx.Error() 如果错误是context.Canceled ,那么上下文已经使用cancel() function 取消了。如果是context.DeadlineExceeded ,那么它超时了。

要检查上下文是否已被取消或超时,请使用:

select {
   case <-ctx.Done():
       // canceled or timed out
   default:
       // So the select will not block
}

ctx.Done()在达到超时或调用取消函数时触发。

根据文档

当应取消代表此上下文完成的工作时,Done 返回一个关闭的通道。

你可以试试这段代码:

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
    defer cancel()
    for {
        select {
        case <-ctx.Done():
            fmt.Println(ctx.Err())
            return
        default:
            fmt.Println("do something")
            time.Sleep(time.Second)
        }
    }
}

output 应该是:

do something
do something
context deadline exceeded

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM