context 上下文深入
context.Background/TODO、WithCancel/WithTimeout/WithValue、链路传递
context 上下文深入
context.Context 是 Go 并发和网络编程的基石——传递取消信号、超时控制、请求级数据。
学完本章你将: 掌握 context.Background/TODO、WithCancel/WithTimeout/WithValue。
四种创建方式
go
package main
import (
"context"
"fmt"
"time"
)
func main() {
// Background —— 根 context(main/初始化用)
ctx := context.Background()
// WithCancel —— 手动取消
ctx, cancel := context.WithCancel(ctx)
defer cancel() // 确保释放资源
// WithTimeout —— 超时自动取消
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
// WithDeadline —— 指定截止时间
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(5*time.Second))
defer cancel()
}
取消传播
go
func worker(ctx context.Context, name string) {
for {
select {
case <-ctx.Done(): // 收到取消信号
fmt.Println(name, "退出")
return
default:
fmt.Println(name, "工作中...")
time.Sleep(500 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
go worker(ctx, "A")
go worker(ctx, "B")
time.Sleep(2 * time.Second)
cancel() // 同时取消 A 和 B
time.Sleep(time.Second)
}
WithValue —— 传递请求级数据
go
type contextKey string // 自定义 key 类型——防止冲突
ctx := context.WithValue(context.Background(), contextKey("userID"), 42)
// 取出
if userID, ok := ctx.Value(contextKey("userID")).(int); ok {
fmt.Println("User ID:", userID)
}
// ⚠️ WithValue 只适合传递请求范围的数据(如 trace ID)
// 不要用来传函数参数——破坏类型安全