Go:context.Context

什么是 context

context 是 Go 标准库中用来管理任务生命周期跨 API 数据传递的工具。它的主要应用场景是在并发编程中,尤其是处理像 HTTP 请求这样有超时限制或需要手动取消的任务。

为了更通俗地理解,可以把 context 想象成一个任务的「管理员」,它可以:

  1. 通知任务何时结束(比如超时或取消时)。
  2. 传递一些全局信息(比如用户身份或配置)。

从常用例子开始

1. HTTP 请求中的超时控制

假设我们正在写一个 HTTP 服务器,客户端请求要求超时 2 秒:

package main

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

func handler(w http.ResponseWriter, r *http.Request) {
	// 创建一个带超时的 context,2 秒后自动取消
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel() // 确保函数结束时释放资源

	// 模拟一个耗时任务
	select {
	case <-time.After(3 * time.Second):
		fmt.Fprintln(w, "Finished task")
	case <-ctx.Done(): // 当 context 超时时,Done 会被触发
		http.Error(w, "Request timed out", http.StatusRequestTimeout)
	}
}

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

运行逻辑:

  • 如果任务完成时间超过 2 秒,ctx.Done() 会收到取消信号,及时停止任务,避免资源浪费。
  • context 帮助我们优雅地处理超时。

2. 跨 API 传递请求信息

context 还能传递数据,比如用户的认证信息或请求 ID:

package main

import (
	"context"
	"fmt"
)

func main() {
	// 创建一个带键值对的 context
	ctx := context.WithValue(context.Background(), "userID", 42)

	// 传递 context 到其他函数
	processRequest(ctx)
}

func processRequest(ctx context.Context) {
	// 从 context 中取出数据
	if userID := ctx.Value("userID"); userID != nil {
		fmt.Println("Processing request for user:", userID)
	} else {
		fmt.Println("No user ID found")
	}
}

运行逻辑:

  • 主函数设置了 userID,传递给 processRequest
  • 在子函数中,可以从 context 中提取出该数据,实现信息的跨 API 共享。

context 的关键功能

  1. 取消信号
    使用 context.WithCancel 来手动通知任务停止:

    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        time.Sleep(1 * time.Second)
        cancel() // 通知任务取消
    }()
    
    <-ctx.Done() // 阻塞,直到取消信号被触发
    fmt.Println("Task cancelled")
    
  2. 超时控制
    使用 context.WithTimeout 自动取消任务:

    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    
    select {
    case <-time.After(3 * time.Second):
        fmt.Println("Task completed")
    case <-ctx.Done():
        fmt.Println("Timeout:", ctx.Err()) // 输出超时错误
    }
    
  3. 数据传递
    使用 context.WithValue 跨 API 传递数据。


为什么需要 context

  1. 解决并发中的控制问题
    在 Go 中,任务往往是通过 goroutine 并发执行的,但如何优雅地终止任务?传统方法可能需要复杂的 channel 通信,而 context 提供了一个统一的接口。

  2. 统一超时和取消机制
    无需手动编写超时逻辑或全局变量,context 内置了这些功能。

  3. 跨 API 共享数据
    context 可以像字典一样存储键值对,让函数间更方便地传递信息。


常用场景

  1. HTTP 请求处理:
    控制请求的超时、取消和数据传递。

  2. 数据库操作:
    遇到慢查询时,设置超时或取消。

  3. 微服务通信:
    在分布式系统中传递请求 ID 或认证信息。

  4. 并发任务协调:
    例如多个 goroutine 需要根据同一个取消信号停止。


总结

通俗来说,context 是 Go 语言中用来管理任务生命周期传递信息的工具,它让我们可以更方便地实现超时控制、手动取消和跨 API 数据共享,简化了并发编程中的复杂操作。

posted @   牛马chen  阅读(76)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示