开发者

go语言中context的使用说明

目录
  • 概述
  • 主要功能
  • Context 的三种基本类型
  • 常见用法举例
    • context.WithCancel传递取消信号
    • 使用 WithTimeout 设置超时
    • 使用 WithValue 传递数据
  • 常用的相关方法和常量
    • context如何控制goroutine的执行
      • 总结

        概述

        Context 是 Go 语言中非常重要的一个概念,它主要用于跨多个函数或 goroutine 传递 取消信号超时控制截止时间请求范围数据

        在并发编程中,Context 提供了更好的控制和管理,尤其是当你需要在多个 goroutine 之间传递状态或进行资源清理时。

        主要功能

        Context 主要有以下几个功能:

        • 取消信号:通知一个或多个 goroutine 取消它们正在执行的工作。
        • 超时和截止时间:指定操作的最大执行时间,防止阻塞操作过长时间。
        • 传递请求范围数据:携带请求范围内的数据,通常用于请求 ID、用户信息等。

        Context 的三种基本类型

        Go 中的 context 包提供了几种常用的 Context 类型:

        • context.Background():通常作为根 Context,表示没有附加数据或取消信号的上下文。它通常是根上下文,作为其他上下文的父上下文。
        • context.TODO(NmYmJiujGQ):表示你暂时没有确定使用什么样的 Context,通常用于占位。
        • context.WithCancel(parent):创建一个可取消的 Context,并返回一个取消函数,当你调用这个函数时,Context 会被取消。
        • context.WithTimeout(parent, timeout):创建一个带有超时的 Context,指定最大等待时间,超过这个时间会自动取消。
        • context.WithDeadline(parent, deadline):指js定一个具体的截止时间,超过这个时间后自动取消。
        • context.WithValue(parent, key, value):创建一个携带键值对数据的 Context,通常用于传递请求级别的数据(例如,用户身份信息)。

        常见用法举例

        context.WithCancel传递取消信号

        主要场景:

        • 手动控制并发任务的终止
        • 优雅退出:在一个任务中途需要取消时,用 cancel() 通知所有相关的 goroutine 停止执行。

        代码示例:

        package main
        
        import (
        	"context"
        	"fmt"
        	"time"
        )
        
        func main() {
        	// 创建一个可取消的 Context
        	ctx, cancel :=NmYmJiujGQ context.WithCancel(context.Background())
        
        	// 启动一个 goroutine,监听取消信号
        	go func(ctx context.Context) {
        		for {
        			select {
        			case <-ctx.Done(): // 检测到取消信号
        				fmt.Println("Goroutine stopped")
        				return
        			default:
        				// 模拟工作
        				fmt.Println("Working...")
        				time.Sleep(1 * time.Second)
        			}
        		}
        	}(ctx)
        
        	// 主线程等待 3 秒后取消
        	time.Sleep(3 * time.Second)
        	cancel() // 发送取消信号
        
        	// 等待 goroutine 退出
        	time.Sleep(1 * time.Second)
        	fmt.Println("Main program exited")
        }

        解释

        1. 主线程创建了一个带有取消功能的上下文 ctx
        2. 子 goroutine 使用 ctx.Done() 监听取消信号。
        3. 主线程 3 秒后调用 cancel(),子 gorouhttp://www.devze.comtine 检测到信号后优雅退出。

        使用 WithTimeout 设置超时

        context.WithTimeout 用于设置一个超时时间,超过该时间后 Context 会自动取消,适用于需要限时执行的操作。防止某些任务阻塞的时间过长。

        package main
        
        import (
        	"context"
        	"fmt"
        	"time"
        )
        
        func main() {
        	// 设置超时时间为 2 秒
        	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
        	defer cancel() // 确保超时后取消 ctx
        
        	// 启动一个模拟长时间执行的任务
        	go longRunningTask(ctx)
        
        	// 等待超时或任务完成
        	<-ctx.Done()
        	if ctx.Err() == context.DeadlineExceeded {
        		fmt.Println("Timeout reached")
        	}
        }
        
        func longRunningTask(ctx context.Context) {
        	select {
        	case <-time.After(3 * time.Second): // 模拟长时间任务
        		fmt.Println("Task completed")
        	case <-ctx.Done():
        		// 任务被取消或超时
        		fmt.Println("Task cancelled due to timeout")
        	}
        }

        WithDeadline的用法和Withtimeout用法类似,只是一个传入的参数是等待时间,一个传入的参数是截止时间。

        使用 WithValue 传递数据

        context.WithValue 可以在 Context 中存储键值对,通常用于传递请求级别的数据(例如用户身份、请求 ID 等)。

        package main
        
        import (
        	"context"
        	"fmt"
        )
        
        func main() {
        	// 创建一个上下文并传递数据
        	ctx := context.WithValue(context.Background(), "userID", 12345)
        
        	// 将 ctx 传递给其他函数
        	processRequest(ctx)
        }
        
        func processRequest(ctx context.Context) {
        	// 从 ctx 中提取数据
        	userID := ctx.Value("userID")
        	if userID != nil {
        		fmt.Println("User ID:", userID)
        	} phpelse {
        		fmt.Println("No user ID found")
        	}
        }

        使用 WithValue 小心context.WithValue 并不是用于传递大量数据的,主要用于传递少量的上下文信息,比如请求 ID 等。

        如果传递过多的数据,会使得 Context 难以维护。

        常用的相关方法和常量

        • ctx.Done():返回一个 channel,当 Context 被取消时该 channel 会被关闭。
        • ctx.Err():返回 Context 被取消的错误,通常是 context.Canceledcontext.DeadlineExceeded
        • ctx.Value(key):获取在 Context 中传递的数据。

        context如何控制goroutine的执行

        从上面的举例可以看出,在每个goroutine中通过判断ctx.Done()是否被执行,从而知道任务是否被取消/超时/到达截止日期。

        Context 被取消(调用 cancel())或超时/到达截止时间时,ctx.Done() 所关联的 channel 会关闭,此时select语句就可以执行ctx.Done()对应的分支。

        总结

        以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜