一、介绍

我们在命令行 输入 go doc context 可以看到多 context包的介绍。
context上下问,是连接不同的goroutine,让每个协程可以有父子关系,并且拥有自己的独特的值
WithValue(),或者处理超时WithTimeout(),定时WithDeadline(),取消协程WithCancel()操作。
在go官方博客https://go.dev/blog/context也有想起的介绍。

源码地址 src/context/context.go
在context包里,共有4种类型的上下文

上下文如何获取作用
emptyCtxBackground()或TODO()初始化父级上下文
valueCtxWithValue()初始化一个带key,value子级上下文
cancelCtxWithCancel()初始化一个可以取消子级上下文
timerCtxWithDeadline()或WithTimeout()初始化一个带有定时以及可以取消子级上下文

从协程的角度来看如下图:
image.png

从上下文的角度来看如下图:
image.png

二、emptyCtx 初始化默认父级上下文

源码如下:

var (
    background = new(emptyCtx)
    todo       = new(emptyCtx)
)

func Background() Context {
    return background
}
func TODO() Context {
    return todo
}

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}

type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
    return
}
func (*emptyCtx) Done() <-chan struct{} {
    return nil
}
func (*emptyCtx) Err() error {
    return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
    return nil
}
func (e *emptyCtx) String() string {
    switch e {
    case background:
        return "context.Background"
    case todo:
        return "context.TODO"
    }
    return "unknown empty Context"
}

emptyCtx 是是一个实现了Context接口的 上下文。
没有做什么逻辑,只是为了实现一个变量,能够让Background()和 TODO()调用。

三、valueCtx,基于parent,派生一个带k,v的上下文context

我们使用

WithValue(parent Context, key, val interface{}) Context

来派生一个带key,val的子context,使用如下:

import (
    "context"
    "testing"
)

type User struct {
    Name string
}

func TestName(t *testing.T) {
    parentContext := context.Background()
    kvContext := context.WithValue(parentContext, "user", User{Name: "hisheng"})
    t.Log(kvContext.Value("user")) //{hisheng}
}

源码如下:

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}
}

type valueCtx struct {
    Context
    key, val interface{}
}
func (c *valueCtx) String() string {
    return contextName(c.Context) + ".WithValue(type " +
        reflectlite.TypeOf(c.key).String() +
        ", val " + stringify(c.val) + ")"
}

func (c *valueCtx) Value(key interface{}) interface{} {
    if c.key == key {
        return c.val
    }
    return c.Context.Value(key)
}

源码通过 WithValue(parent Context, key, val interface{}),派生一个valueCtx,
valueCtx拥有属性key,val,在此时初始化赋值,并且通过组合的模式可以调用Context的方法。
valueCtx比较独特有一个 Value(key interface{}) 方法,用来获取存进去的值。

四、cancelCtx,基于parent,派生一个可取消的上下文context

五、timerCtx,基于parent,派生一个带有定时以及可取消的上下文context

谢谢您的观看,欢迎关注我的公众号。

image.png


海生
104 声望32 粉丝

与黑夜里,追求那一抹萤火。