Go语言Context应用全攻略:异步编程利器

概述在 Go 语言中,Context(上下文)是一个非常重要的概念,特别是在处理请求时 。
允许在请求的整个生命周期内传递数据、控制请求的取消、处理超时等 。
本文将介绍 Go 语言中 Context 的使用,帮助更好地理解与处理请求的传递与控制 。
主要内容包括
Context 基础
Context 创建与传递
Context 的超时与取消
Context 的链式操作
Context 在并发中的应用
Context 的应用场景
最佳实践与注意事项
1. Context 基础在 Go 语言中,context.Context 接口定义了一个请求的上下文 。
它包含了请求的截止时间、取消信号和请求的数据 。
使用 Context 可以在请求之间有效地传递数据,同时也可以控制请求的生命周期 。
type Context interface {Deadline() (deadline time.Time, ok bool)Done() <-chan struct{}Err() errorValue(key interface{}) interface{}}Context 接口包含了四个方法:Deadline() 返回 Context 的截止时间
Done() 返回一个通道 , 它会在 Context 被取消或超时时关闭
Err() 返回 Context 的错误信息,Value(key) 返回 Context 中与 key 关联的值 。
2. Context 创建与传递2.1 创建和传递 Contextpackage mAInimport ("context""fmt""time")func main() {// 创建一个根ContextrootContext := context.Background()// 创建一个带有超时时间的Context,这里设置超时时间为2秒ctx, cancel := context.WithTimeout(rootContext, 2*time.Second)defer cancel()// 在新的goroutine中执行任务go func(ctx context.Context) {select {case <-time.After(3 * time.Second):fmt.Println("任务完成")case <-ctx.Done():fmt.Println("任务取消或超时")}}(ctx)// 等待一段时间,模拟程序运行time.Sleep(5 * time.Second)}在这个例子中,创建了一个带有 2 秒超时时间的 Context,并在一个新的 goroutine 中执行一个任务 。
在主 goroutine 中,等待了 5 秒,因此任务在超时之前完成,所以会输出"任务完成" 。
2.2 使用 WithValue 传递数据package mainimport ("context""fmt")type key stringfunc main() {// 创建一个根ContextrootContext := context.Background()// 使用WithValue传递数据ctx := context.WithValue(rootContext, key("userID"), 123)// 在子函数中获取传递的数据getUserID(ctx)}func getUserID(ctx context.Context) {// 从Context中获取数据if userID, ok := ctx.Value(key("userID")).(int); ok {fmt.Println("UserID:", userID)} else {fmt.Println("UserID不存在")}}在这个示例中,使用 WithValue 方法在 Context 中传递了一个 userID 的值,并在 getUserID 函数中成功获取并打印了这个值 。
3. Context 的超时与取消3.1 设置请求超时时间package mainimport ("context""fmt""time")func main() {// 创建一个根ContextrootContext := context.Background()// 创建一个超时时间为2秒的ContexttimeoutCtx, _ := context.WithTimeout(rootContext, 2*time.Second)// 创建一个手动取消的ContextcancelCtx, cancel := context.WithCancel(rootContext)defer cancel()// 在新的goroutine中执行任务go func(ctx context.Context) {select {case <-time.After(3 * time.Second):fmt.Println("任务完成")case <-ctx.Done():fmt.Println("任务取消或超时")}}(timeoutCtx)// 在另一个goroutine中执行任务go func(ctx context.Context) {select {case <-time.After(1 * time.Second):fmt.Println("另一个任务完成")case <-ctx.Done():fmt.Println("另一个任务取消")}}(cancelCtx)// 等待一段时间 , 模拟程序运行time.Sleep(5 * time.Second)}在上面例子中,用 WithTimeout 方法创建了一个带有 2 秒超时时间的 Context 。
在任务的 goroutine 中,用 select 语句监听了超时和 Context 的取消两个事件,以便及时响应 。
3.2 处理请求取消package mainimport ("context""fmt""time")func main() {// 创建一个根ContextrootContext := context.Background()// 创建一个可以手动取消的Contextctx, cancel := context.WithCancel(rootContext)defer cancel()// 在新的goroutine中执行任务go func(ctx context.Context) {select {case <-time.After(3 * time.Second):fmt.Println("任务完成")case <-ctx.Done():fmt.Println("任务取消")}}(ctx)// 等待一段时间,手动取消任务time.Sleep(2 * time.Second)cancel()// 等待一段时间 , 模拟程序运行time.Sleep(1 * time.Second)}在上面例子中 , 使用 WithCancel 方法创建了一个可以手动取消的 Context 。
在主函数中,等待了 2 秒后,手动调用 cancel 函数取消了任务 。
这时,在任务的 goroutine 中,ctx.Done() 会接收到取消信号,从而退出任务 。


推荐阅读