golang 中常用的超时控制的方案示例

go 中,我们很容易就可以实现超时控制,今天分享2种解决方案:

  • 1.select + time.After
  • 2.select + context

其实两种方案中,我们都是通过 channel 来控制的,在方案1中,对于 time.After, 通过返回一个只读 <- chan Time 实现,而 context 中,则通过 context.Done() 实现,通过返回 <- chan struct{} 信号实现,

下面看看函数签名:
time.After
可以看到,只需要传入一个时间的duration即可。

// go1.19/src/time/sleep.go
func After(d Duration) <-chan Time {
	return NewTimer(d).C
}

context.Done
这其实是通过实现 context接口的 timeCtx

接下来看看超时控制的相关代码实现。

1.select + time.After

package main

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

func main()  {
	fmt.Printf("[%s] start...\n", time.Now().Format(time.RFC3339))
	taskCh := make(chan int)
	go func() {
		time.Sleep(5*time.Second)
		taskCh <- 1
	}()

	select {
	case data := <- taskCh:
		fmt.Println(data)
	case <- time.After(time.Second):
		fmt.Println("timeout!")
	}
	fmt.Printf("[%s] end...\n", time.Now().Format(time.RFC3339))
}

我们通过实现一个耗时的task实现任务耗时,在time.After中传入1s的超时,到1s时,该case先收到信号,从而结束整个执行。

2.select + context

package main

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

func main()  {
	fmt.Printf("[%s] start...\n", time.Now().Format(time.RFC3339))
	ctx, cancel := context.WithTimeout(context.Background(), 3 * time.Second)
	defer cancel()
	taskCh := make(chan int)
	go func() {
		time.Sleep(5*time.Second)
		taskCh <- 1
	}()

	select {
	case data := <- taskCh:
		fmt.Println(data)
	case <- ctx.Done():
		fmt.Println("timeout!")
	}
	fmt.Printf("[%s] end...\n", time.Now().Format(time.RFC3339))
}

类似于上一个方案,我们只是在context中传入3s的超时时长,到了时间后,就会收到 ctx.Done(),进而结束执行。

posted on 2023-04-21 14:25  进击的davis  阅读(585)  评论(0编辑  收藏  举报

导航