wx

关注公众号

context


Golang 标准库 - context

context 包定义了上下文类型,用于在 API 边界和进程之间传递截止时间、取消信号和请求范围的值。

主要功能说明:

  1. 创建 Context

    • Background() 根 Context
    • TODO() 占位 Context
    • WithCancel() 可取消的 Context
    • WithTimeout() 带超时的 Context
    • WithDeadline() 带截止时间的 Context
  2. 取消信号

    • Done() 返回取消通道
    • Err() 返回取消原因
    • 调用 cancel 函数取消
  3. 传递值

    • WithValue() 添加键值对
    • Value() 获取值
  4. 超时控制

    • 设置操作截止时间
    • 优雅地处理超时

// 模拟耗时操作
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")
	}
}
如有疑问关注公众号给我留言
wx

关注公众号

©2017-2023 鲁ICP备17023316号-1 Powered by Hugo