cover_image

Context超时处理应该这么做

堆栈future
2022年12月19日 06:07

超时处理应该这么做

1、超时处理有问题代码

只通过select监听超时信号,没有处理正常逻辑处理。

package main

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

var wg sync.WaitGroup

func main() {
 // 定义一个3s超时context 所有衍生出来的goroutine必须在3s内完成 否则会cancel掉
 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
 defer cancel()

 go func() {
  wg.Add(2)
  go watch(ctx, 1)
  go watch(ctx, 2)
  wg.Wait()
 }()

// 这里有问题,因为不管是超时还是未超时都会进入<-ctx.Done() 也就是都会等待3s 这不是我们想要的
 select {
 case <-ctx.Done():
  fmt.Printf("watch %d %s\n", 0, ctx.Err())
 }

 fmt.Println("finished")
}

func watch(ctx context.Context, flag int) {
 defer wg.Done()

 func() {
  fmt.Printf("doing something flag:%d\n", flag)
  time.Sleep(10*time.Second)
  fmt.Println("finished flag:", flag)
 }()
}

2、如何解决?

很简单,就是在所有goroutine结束之后发送一个done信号给主goroutine,这样select就会监听到这个信号,从而安全退出。

// 增加done信号
 done := make(chan struct{})
 go func() {
  wg.Add(2)
  go watch(ctx, 1)
  go watch(ctx, 2)
  wg.Wait()
  done <- struct{}{} // 发送done信号
 }()

 select {
 case <-done: // 接受done信号
  fmt.Println("Done")
 case <-ctx.Done():
  fmt.Printf("watch %d %s\n", 0, ctx.Err())
 }


继续滑动看下一个
堆栈future
向上滑动看下一个