context
Golang 标准库 - context
context 包定义了上下文类型,用于在 API 边界和进程之间传递截止时间、取消信号和请求范围的值。
主要功能说明:
-
创建 Context:
Background()根 ContextTODO()占位 ContextWithCancel()可取消的 ContextWithTimeout()带超时的 ContextWithDeadline()带截止时间的 Context
-
取消信号:
Done()返回取消通道Err()返回取消原因- 调用 cancel 函数取消
-
传递值:
WithValue()添加键值对Value()获取值
-
超时控制:
- 设置操作截止时间
- 优雅地处理超时
// 模拟耗时操作
func longRunningProcess(ctx context.Context, id int) {
for i := 0; i < 10; i++ {
select {
case <-ctx.Done():
fmt.Printf("Process %d: cancelled: %v\n", id, ctx.Err())
return
default:
fmt.Printf("Process %d: step %d\n", id, i)
time.Sleep(300 * time.Millisecond)
}
}
fmt.Printf("Process %d: completed\n", id)
}
func main() {
// 1. 使用 WithCancel
fmt.Println("=== WithCancel ===")
ctx, cancel := context.WithCancel(context.Background())
go longRunningProcess(ctx, 1)
time.Sleep(1 * time.Second)
fmt.Println("Main: cancelling context")
cancel() // 取消所有派生的 goroutine
time.Sleep(500 * time.Millisecond)
// 2. 使用 WithTimeout
fmt.Println("\n=== WithTimeout ===")
ctx2, cancel2 := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel2()
done := make(chan bool)
go func() {
longRunningProcess(ctx2, 2)
done <- true
}()
select {
case <-done:
fmt.Println("Process completed")
case <-ctx2.Done():
fmt.Println("Timeout:", ctx2.Err())
}
// 3. 使用 WithDeadline
fmt.Println("\n=== WithDeadline ===")
deadline := time.Now().Add(1 * time.Second)
ctx3, cancel3 := context.WithDeadline(context.Background(), deadline)
defer cancel3()
go longRunningProcess(ctx3, 3)
select {
case <-ctx3.Done():
fmt.Println("Deadline reached:", ctx3.Err())
case <-time.After(3 * time.Second):
fmt.Println("Waited too long")
}
// 4. 传递值
fmt.Println("\n=== WithValue ===")
ctx4 := context.WithValue(context.Background(), "userID", "12345")
ctx4 = context.WithValue(ctx4, "requestID", "abc-xyz")
processWithValue(ctx4)
// 5. 嵌套 Context
fmt.Println("\n=== 嵌套 Context ===")
rootCtx := context.Background()
ctxA, cancelA := context.WithTimeout(rootCtx, 5*time.Second)
defer cancelA()
ctxB, cancelB := context.WithCancel(ctxA)
defer cancelB()
go func() {
<-ctxB.Done()
fmt.Println("Context B cancelled:", ctxB.Err())
}()
cancelB() // 取消 B,A 的超时仍然有效
time.Sleep(100 * time.Millisecond)
}
func processWithValue(ctx context.Context) {
userID := ctx.Value("userID")
requestID := ctx.Value("requestID")
if userID != nil {
fmt.Printf("User ID: %v\n", userID)
}
if requestID != nil {
fmt.Printf("Request ID: %v\n", requestID)
}
// 不存在的 key
if val := ctx.Value("nonexistent"); val == nil {
fmt.Println("Key 'nonexistent' not found")
}
}