Skip to content

context

context.Context 是一个接口

主要功能:

  1. 取消控制(Cancel)
  2. 超时 / 截止时间(Timeout / Deadline)
  3. 携带数据(Value)
  4. 统一管理多层 goroutine 生命周期

创建

函数功能
context.Background()空 context,通常作为根 context 使用
context.TODO()占位 context,表示还没决定使用哪种 context
context.WithCancel(parent)基于父 context 创建可取消 context,返回 ctx, cancel()
context.WithTimeout(parent, duration)自动在 duration 后取消
context.WithDeadline(parent, time)在指定时间点取消,类似 WithTimeout
context.WithValue(parent, key, value)绑定 key-value 数据,适用于请求作用域

context.Background()context.TODO() 只是一个起点,什么都没有。

WithCancel / WithTimeout / WithDeadline 会基于 parent 创建新的 context,但是会继承 deadline、取消信号。

父可以影响子,但是子不会触发父

type cancelCtx struct {
    Context         // 嵌入父 context
    done chan struct{}
    mu sync.Mutex
    children map[canceler]struct{}
}
  1. child 保存 parent 的引用
  2. parent 的 children 里注册 child

所以是双向关系,但是是单向影响。

主动取消

go
ctx, cancel := context.WithCancel(context.Background())

go func() {
	for {
		select {
		case <-ctx.Done():
			fmt.Println("goroutine exit:", ctx.Err())
			return
		default:
			fmt.Println("working...")
			time.Sleep(500 * time.Millisecond) // 没有这个 Sleep,会密密麻麻一直打印
		}
	}
}()

time.Sleep(2 * time.Second)
cancel() // 主动取消
time.Sleep(1 * time.Second)

超时

go
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

select {
case <-time.After(3 * time.Second):
    fmt.Println("Finished work")
case <-ctx.Done():
    fmt.Println("Timeout:", ctx.Err())
}

“Finished work” 不会被打印

父有 timeout,子并不会有。但是父 Done,子也会 Done,所以虽然没有,但是却有好像有,只是实际上没有。

DDL

接受一个固定时间, 然后到了时间 Done

Value

Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it.

value 只是请求级别的横切信息,不是万能袋。

只能存kv,是链接结构。子可以覆盖父,子也能访问到父到value。