Go并发编程-context底层实现

cancelCtx实现

cancelCtx 也是典型的装饰器模式:在已有Context 的基础上,加上取消的功能。
核心实现:

  • Done方法是通过类似于 double-check 的机制写的。这种原子操作和锁结合的用法比较罕见。(思考:能不能换成读写锁?

  • 利用 children来维护了所有的衍生节点,难点就在于它是如何维护这个衍生节点。

    double-check-1:
    done是一个原子变量,有load()方法。如果channel不为nil,即放返回。
    double-check-2:
    为nil则使用锁,加载channel并store到原子变量。

Go并发编程-context底层实现_第1张图片

children: 核心是儿子把自己加进去父亲的children字段里面。

但是因为Context里面存在非常多的层级,所以父亲不一定是 cancelCtx,因此本质上是找最近属于 cancelCtx 类型的祖先,然后儿子把自己加进去。

cancel就是遍历children,挨个调用cancel。然后儿子调用孙子的cancel,子子孙孙无穷匮也。

Go并发编程-context底层实现_第2张图片
parentCancelCtx 寻找第一个待cancel的父辈context,并加入children。

cancel

核心的cancel方法,做了两件事:

  • 遍历所有的children
  • 关闭done这个channel:这个符合谁创建谁关闭的原则‘
    (利用了被关闭的channel永远能读到零值的特性,完成信号的发放)
    Go并发编程-context底层实现_第3张图片

timerCtx实现

timerCtx也是装饰器模式:在已有cancelCtx的基础上增加了超时的功能。
实现要点:

  • WithTimeout 和 WithDeadline 本质一样WithDeadline 里面,
  • 在创建 timerCtx 的时候利用 time.AfterFunc 来实现超时

Go并发编程-context底层实现_第4张图片

context包使用注意

  • 一般只用做方法参数,而且是作为第一个参数;
  • 所有公共方法,除非是 util, helper 之类的方法(纯粹工具类,计算不会花费很长时间的 ) ,否则都加上 context 参数。
  • 注意当与第三方,如调用方、数据库、Redis等打交道,一定要加context参数,以便于超时控制、链路控制等。
  • 不要用作结构体字段,除非你的结构体本身也是表达一个上下文的概念。
    (如HttpRequest 可以加到结构体字段)

context 提问要点

context.Context 使用场景:上下文传递(KV)控制
context.Context 原理:

  • 父亲如何控制儿子:通过儿子主动加入到父亲的children里面,父亲只需要遍历就可以。
  • valueCtx和timeCtx的原理(timeCtx在cancelCtx基础上加time.AfterFunc)

context四个核心方法API使用场景,在什么时候使用,有什么样的特性。关注一下。

context四个接口核心方法,如Err的返回值。

你可能感兴趣的:(Go,golang)