WithDeadline 方法在创建 timerCtx 的过程中,判断了父上下文的截止日期与当前日期,并通过 time.AfterFunc 创建定时器,当时间超过了截止日期后会调用 timerCtx.cancel 方法同步取消信号。
WithCancel、WithDeadline以及WithTimeout都返回了一个Context以及一个CancelFunc函数,返回的Context也就是我们当前基于parent创建了cancelCtx或则timerCtx,通过CancelFunc我们可以取消当前Context,即使timerCtx还未超时。
4.9 WithValue()https://www.cnblogs.com/qcrao-2018/p/11007503.html
//创建 valueCtx 的函数 func WithValue(parent Context, key, val interface{}) Context { if key == nil { panic("nil key") } if !reflectlite.TypeOf(key).Comparable() { panic("key is not comparable") } return &valueCtx{parent, key, val} } func (c *valueCtx) String() string { return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) }对 key 的要求是可比较,因为之后需要通过 key 取出 context 中的值,可比较是必须的。通过层层传递 context,最终形成这样一棵树.
和链表有点像,只是它的方向相反:Context 指向它的父节点,链表则指向下一个节点。通过 WithValue 函数,可以创建层层的 valueCtx,存储 goroutine 间可以共享的变量。取值的过程,实际上是一个递归查找的过程:
func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) }它会顺着链路一直往上找,比较当前节点的 key 是否是要找的 key,如果是,则直接返回 value。否则,一直顺着 context 往前,最终找到根节点(一般是 emptyCtx),直接返回一个 nil。所以用 Value 方法的时候要判断结果是否为 nil。因为查找方向是往上走的,所以,父节点没法获取子节点存储的值,子节点却可以获取父节点的值。WithValue 创建 context 节点的过程实际上就是创建链表节点的过程
参考https://www.cnblogs.com/qcrao-2018/p/11007503.html
https://blog.golang.org/context
https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-context/
https://studygolang.com/articles/13598