一、介绍
我们在命令行 输入 go doc context 可以看到多 context包的介绍。
context上下问,是连接不同的goroutine,让每个协程可以有父子关系,并且拥有自己的独特的值
WithValue(),或者处理超时WithTimeout(),定时WithDeadline(),取消协程WithCancel()操作。
在go官方博客https://go.dev/blog/context也有想起的介绍。
源码地址 src/context/context.go
在context包里,共有4种类型的上下文
上下文 | 如何获取 | 作用 |
---|---|---|
emptyCtx | Background()或TODO() | 初始化父级上下文 |
valueCtx | WithValue() | 初始化一个带key,value的子级上下文 |
cancelCtx | WithCancel() | 初始化一个可以取消的子级上下文 |
timerCtx | WithDeadline()或WithTimeout() | 初始化一个带有定时以及可以取消的子级上下文 |
从协程的角度来看如下图:
从上下文的角度来看如下图:
二、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{}) 方法,用来获取存进去的值。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。