使用Go语言的WithTimeout函数如何检测超时发生

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

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使这个函数超时。

我还没有找到如何在超时发生时设置err的方法。

我查看了Go文档中的示例(https://pkg.go.dev/context#example-WithTimeout),但我并没有真正理解它。<-ctx.Done()这种情况是否总是表示超时已经发生?这个示例似乎暗示相反-<-ctx.Done()表示代码已经完成而没有超时。

我想要澄清一下如何检测使用context.WithTimeout运行的代码是否已经超时。

此外,我想了解在我的代码中应该在哪里检查超时是否发生。我最初的想法是将此检查放在函数的末尾,但这样是否太晚了?

英文:

I have the following Go code:

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
}

I am trying to cause this function to timeout using context.WithTimeout.

What I have not been able to figure out is how to set err if the timeout occurs.

I looked at the example in the Go docs but I did not really understand it. Does the &lt;-ctx.Done() case always mean that the timeout was reached? This example seems to suggest the opposite - that &lt;-ctx.Done() means the code ran to completion without timing out.

I am looking for clarification on how to detect when code run with context.WithTimeout has or has not timed out.

Additionally, I would like to understand where in my code I should check if the timeout occurred. My first thought was to put this check at the end of the function, but would that be putting the check too late?

答案1

得分: 2

要检测上下文是否超时,请检查ctx.Error()。如果错误是context.Canceled,则表示上下文已使用cancel()函数取消。如果是context.DeadlineExceeded,则表示已超时。

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

select {
   case <-ctx.Done():
       // 已取消或已超时
   default:
       // 为了避免阻塞select语句
}
英文:

To detect if the context has timed out, check ctx.Error(). If the error is context.Canceled, then the context has been canceled using the cancel() function. If it is context.DeadlineExceeded, then it timed out.

To check if the context has been canceled or timed out, use:

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

答案2

得分: 1

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

根据文档

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

英文:

ctx.Done() fires when the timeout is reached or the cancel func is called.

Per the docs:

> Done returns a channel that's closed when work done on behalf of this context should be canceled.

答案3

得分: 0

你可以尝试这段代码:

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("做一些事情")
			time.Sleep(time.Second)
		}
	}
}

输出应该是:

做一些事情
做一些事情
上下文超时
英文:

You can try this code:

package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

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

The output should be:

do something
do something
context deadline exceeded

huangapple
  • 本文由 发表于 2023年1月26日 23:16:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75248101.html
匿名

发表评论

匿名网友

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

确定