Go的渐渐深入(一) | 青训营

64 阅读3分钟

前言

  • 意在进一步分析在go项目中常见的一些内容
  • 稍微深入一点点学习

ctx参数

  • 核心在于Context接口
  • 定义Context为interface,携带截止日期,取消信号,以及跨越API边界的请求范围值,重要的是,它的方法能安全地被多个goroutines同时执行
    • 包含四个方法:
      • Done():当接口超时或者调用 cancel方法时,返回一个关闭的channel
      • Err():返回一个错误,执行的表明取消 ctx 的原因。
      • Deadline():返回Context将被取消的时间。
      • Value():返回 key 对应的值或是nil。
    • 实现
      • 有四个结构体实现了这个接口,分别是:
        • emptyCtx
          • 空类型,暴露Background()和TODO()两个方法
          • Background() 作为根 ctx,然后在其基础上再派生出子 ctx
          • 不确定使用哪个 ctx,就使用 TODO()
        • cancelCtx
          • WithCancel(parent Context) (ctx Context, cancel CancelFunc)
          • WithCancel 返回带有新 Done 通道的父级副本
          • 当调用返回的 cancel 函数关闭父上下文的 Done 通道时,返回的 ctx 的 Done 通道将关闭。
          • 注意:由于取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用 cancel
        • timerCtx
          • WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
            • WithDeadline 返回父上下文的副本,并将截止日期调整为不晚于 deadline
              • 如果父级的截止日期已经早于 deadline,则 WithDeadline(parent, deadline) 在语义上等同于 parent
              • 当deadline到期、调用返回的cancel函数时或当父上下文的 Done 通道关闭时,返回的上下文的 Done 通道将关闭。当然需要释放相关的资源,即defer cancel()
          • WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
            • 这个跟DEADLINE相关,就是返回WithDeadline(parent, time.Now().Add(timeout)),需要释放相关的资源,即defer cancel()
        • valueCtx
          • WithValue(parent Context, key, val interface{}) Context
          • WithValue 返回父级的副本,其中与 key 关联的值为 val
          • 键(key)需要可比较,注意,key不应该是字符串类型或者其他内置类型,因为这可能会有使用上下文的包之间发生冲突的可能,应该定义自己的键类型(不是说不能用字符串这些类型,是说你需要去定义type一下键的类型,用新类型名去调用)
          • 为避免分配给interface{},上下文键通常具有具体的 struct{} 类型
          • 导出的上下文键变量的静态类型应该是指针接口

遵循规则

  • 不要将Context放入结构体,应该作为第一个参数传入,命名为ctx
  • 函数允许也不要传入nil的Context,不知道用哪种Context,可以用context.TODO()
  • 使用Value方法应该只用于程序或者接口中传递和请求相关的元数据,不要用它传递一些可选参数
  • 相同Context可以传递给不同goroutine,Context是并发安全的

总结

  • Context接口在我看来比较好的点在于并发执行是安全的,这就省了很多事情了
  • 对于kv值的查找,将值传递到上下文以及存在检索输出,都是很方便使用的一些内容