Golang Context包使用教程

Golang Context包使用教程 Go语言中的context包用于在API边界之间传递请求范围的值、取消信号和截止时间。它可以用来存储元数据、取消信号、超时以及其他请求范围的值。context包提供了一种取消长时间运行操作的方式,以及跨API边界存储元数据的方法。它通常与http包一起使用,以管理HTTP请求的请求范围值和取消信号。

Go语言Context包教程

1 回复

更多关于Golang Context包使用教程的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,context包是处理请求生命周期和跨API边界传递元数据的核心工具。它主要用于管理取消信号、超时和请求范围的值。以下是一个详细的使用示例,涵盖基本创建、超时设置、值传递和取消操作。

1. 创建基础Context

使用context.Background()context.TODO()创建根Context,通常作为请求的起点。

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    // 创建根Context
    ctx := context.Background()
    processRequest(ctx)
}

func processRequest(ctx context.Context) {
    // 模拟处理请求
    fmt.Println("处理请求中...")
}

2. 设置超时和截止时间

使用context.WithTimeoutcontext.WithDeadline设置超时,自动触发取消。

func main() {
    ctx := context.Background()
    // 设置2秒超时
    ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
    defer cancel()

    go handleTask(ctx)
    time.Sleep(3 * time.Second) // 模拟主程序等待
}

func handleTask(ctx context.Context) {
    select {
    case <-time.After(3 * time.Second):
        fmt.Println("任务完成")
    case <-ctx.Done():
        fmt.Println("任务取消:", ctx.Err()) // 输出: context deadline exceeded
    }
}

3. 传递请求范围的值

使用context.WithValue存储和检索请求范围的元数据。

func main() {
    ctx := context.Background()
    // 存储用户ID
    ctx = context.WithValue(ctx, "userID", "12345")
    authUser(ctx)
}

func authUser(ctx context.Context) {
    // 检索值
    if userID := ctx.Value("userID"); userID != nil {
        fmt.Println("用户ID:", userID) // 输出: 用户ID: 12345
    }
}

4. 手动取消操作

使用context.WithCancel创建可手动取消的Context,适用于需要主动终止的场景。

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    go performOperation(ctx)

    time.Sleep(1 * time.Second)
    cancel() // 手动取消操作
    time.Sleep(500 * time.Millisecond)
}

func performOperation(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            fmt.Println("操作终止:", ctx.Err()) // 输出: context canceled
            return
        default:
            fmt.Println("操作执行中...")
            time.Sleep(200 * time.Millisecond)
        }
    }
}

5. 在HTTP请求中的应用

结合http包管理请求生命周期,例如设置服务器端超时。

package main

import (
    "context"
    "net/http"
    "time"
)

func main() {
    http.HandleFunc("/api", apiHandler)
    http.ListenAndServe(":8080", nil)
}

func apiHandler(w http.ResponseWriter, r *http.Request) {
    // 为请求创建带超时的Context
    ctx, cancel := context.WithTimeout(r.Context(), 1*time.Second)
    defer cancel()

    // 将Context传递给处理函数
    result := make(chan string)
    go fetchData(ctx, result)

    select {
    case data := <-result:
        w.Write([]byte("数据: " + data))
    case <-ctx.Done():
        http.Error(w, "请求超时", http.StatusGatewayTimeout)
    }
}

func fetchData(ctx context.Context, result chan<- string) {
    // 模拟耗时操作
    time.Sleep(2 * time.Second)
    result <- "完成"
}

关键点总结

  • 取消传播:Context取消信号会向下传递到所有派生Context。
  • 线程安全:Context是并发安全的,可在多个goroutine中使用。
  • 值传递限制:仅存储请求范围的数据,避免滥用。
  • 错误处理:始终检查ctx.Done()ctx.Err()以处理取消或超时。

这些示例覆盖了Context包的核心用法,可直接用于实际开发中管理goroutine生命周期和请求元数据。

回到顶部