Go 1.17中提出,主要提供子孙goroutine的通知关闭的统一解决方法

  • Context接口

    type Context interface {
      Deadline() // 截止时间
      Done() // 手动Cancel时接收到值
      Err() // 错误
      Value() // 存储值
    }
    
  • Context接口的两个默认实现

    • Background

      顶层Context

    • TODO

      暂时不知道具体使用场景时使用

  • 三种实现方式

    • WithCancel

      // 父goroutine中调用cancel()时,子goroutine的ctx.Done()接收到值,即:关闭的通知信号
      var c = 1
      
      func doSome(i int) error {
        c++
        fmt.Println(c)
        if c > 3 {
          return errors.New("err occur")
        }
        return nil
      }
      
      func speakMemo(ctx context.Context, cancelFunc context.CancelFunc) {
        for {
          select {
          case <-ctx.Done():
            fmt.Printf("ctx.Done")
            return
          default:
            fmt.Println("exec default func")
            err := doSome(3)
            if err != nil {
              fmt.Printf("cancelFunc()")
              cancelFunc()
            }
          }
        }
      }
      
      func main() {
        rootContext := context.Background()
        ctx, cancelFunc := context.WithCancel(rootContext)
        go speakMemo(ctx, cancelFunc)
        time.Sleep(time.Second * 5)
      }
      
    • WithDeadline

      // 指定时间终止,规定还是最终需要主动调用cancel
      const shortDuration = 1 * time.Millisecond
      
      func main() {
          d := time.Now().Add(shortDuration)
          ctx, cancel := context.WithDeadline(context.Background(), d)
      
          // Even though ctx will be expired, it is good practice to call its
          // cancellation function in any case. Failure to do so may keep the
          // context and its parent alive longer than necessary.
          defer cancel()
      
          select {
          case <-time.After(1 * time.Second):
              fmt.Println("overslept")
          case <-ctx.Done():
              fmt.Println(ctx.Err())
          }
      }
      
    • WithValue

      // goroutine直接传值
      func main() {
        type favContextKey string
      
        f := func(ctx context.Context, k favContextKey) {
            if v := ctx.Value(k); v != nil {
                fmt.Println("found value:", v)
                return
            }
            fmt.Println("key not found:", k)
        }
      
        k := favContextKey("language")
        ctx := context.WithValue(context.Background(), k, "Go")
      
        f(ctx, k)
        f(ctx, favContextKey("color"))
      }
      
posted on 2022-09-15 19:29  _tiny_coder  阅读(12)  评论(0编辑  收藏  举报