Go Context浅析

2022-04-17  本文已影响0人  米兰的小铁匠xxm

在日常开发中,我们通常会在函数的第一个参数设置为 ctx context.context,这就是golang 的 Context包,目的是用来传递上下文信息。

context都能干啥

说起go大家第一反应会想到协程,协程也具有父子关系,主协程与子协程之间存在控制、协同、取消的需求,如:

  1. 主协程和子协程之间的通信问题,如主协程取消后通知子协程进行取消
  2. 如何对上下文信息进行传递,如请求头里的用户信息,设备信息等
  3. 控制下游rpc接口的超时时间,因为请求基于协程,下游响应慢时,会导致协程数激增,内存上涨,严重可导致服务不可用。

context便是为解决上述问题而生,它可以传递取消信息、超时时间以及携带kv信息等。

如何创建context

  1. context.Background() 和context.TODO() 创建最基本的context
  2. context.WithCancel 传入父context,返回新的context和用于取消该新context的函数
  3. context.WithTimeout和context.WithDeadline,也是传入父context,返回新的context和用于取消该新context的函数,内部会设置定时器,到达时间后自动触发cancelFunc
  4. context.WithValue:传入父context一对kv,返回一个新的Context,新的Context内部会记录这对kv,供以后查询
func main() {
    root := context.Background() //初始化
    ctx1 := context.WithValue(root, "k1", 1111) //携带kv的新context
    ctx2, cancel1 := context.WithCancel(ctx1) //带取消信号的context
    defer cancel1()
    ctx3, cancel2 := context.WithTimeout(ctx2, 2*time.Second) //带超时信号
    defer cancel2()
    ctx4 := context.WithValue(ctx2, "k2", "2222")
    ctx5 := context.WithValue(ctx4, "k3", "3333")
    ctx6 := context.WithValue(ctx3, "k4", "4444")
    ctx7, cancel3 := context.WithDeadline(ctx4, time.Now().Add(4*time.Second))
    defer cancel3()
    ctx8, cancel4 := context.WithCancel(ctx6)
    defer cancel4()

    fmt.Println(ctx7.Value("k1"))
    fmt.Println(ctx6.Value("k4"))
    fmt.Println(ctx5.Value("k2"))

    fmt.Println(ctx7)

    go func() {
        select {
        case <-ctx7.Done():
            fmt.Println("ctx7 canceled")
        }
    }()

    go func() {
        select {
        // ctx8会在7之前cancel,因为ctx3被cancel了
        case <-ctx8.Done():
            fmt.Println("ctx8 canceled")
        }
    }()

    time.Sleep(5 * time.Second)
}
//输出
1111
4444
2222
context.Background.WithValue(type string, val <not Stringer>).WithCancel.WithValue(type string, val 2222).WithDeadline(2022-04-17 21:54:16.807868 +0800 CST m=+4.000185716 [3.999804083s])
ctx8 canceled
ctx7 canceled

context有哪些接口

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

猜你喜欢

热点阅读