Golang中context包使用场景和示例详解

news/2024/12/5 4:17:33/

之前的文章《Golang中context包基础知识详解》详细介绍了context包的基础知识和使用时需要注意的点,本文结合示例代码讲解一下context包的几种使用场景。

控制子协程退出

context包提供了一种机制,可以在多个goroutine之间进行通信和控制。使用Context包能够有效地控制程序的并发性,提高程序的健壮性和性能。

Golang是没有办法让其他goroutine退出的,goroutine只能自己退出。之所以说context包可以控制子协程退出意思是子协程可以接收到主协程发出的退出信号,然后自己退出。看如下示例代码:

package mainimport ("context""errors""sync"
)func request(ctx context.Context, url string) error {result := make(chan int)err := make(chan error)go func() {// 假如isSuccess是请求返回的结果,成功则通过result传递成功信息,错误通过error传递错误信息isSuccess := trueif isSuccess {result <- 1} else {err <- errors.New("some error happen")}}()select {case <-ctx.Done():// 其他请求失败return ctx.Err()case e := <-err:// 本次请求失败,返回错误信息return ecase <-result:// 本此请求成功,不返回错误信息return nil}
}func main() {ctx, cancel := context.WithCancel(context.Background())// 调用接口aerr := request(ctx, "https://xxx.com/a")if err != nil {return}wg := sync.WaitGroup{}// 调用接口bwg.Add(1)go func() {defer wg.Done()err := request(ctx, "https://xxx.com/b")if err != nil {cancel()}}()// 调用接口cwg.Add(1)go func() {defer wg.Done()err := request(ctx, "https://xxx.com/c")if err != nil {cancel()}}()wg.Wait()
}

首先调用context.WithCancel方法构造了一个Context和返回了一个cancel函数,其他goroutine调用的方法都传入了这个Context作为第一个参数,当主goroutine想要告诉所有goroutine需要退出的时候,通过调用cancel函数把退出的信息告诉所有的goroutine。所有goroutine通过监听ctx.Done返回的channel得到退出信号然后退出。

超时控制

例如查询数据库、调用RPC服务、调用HTTP接口等场景,这些操作都是阻塞的,如果一直不返回数据的话,会影响产品的用户体验。针对这些情况的解决方式通常是设置一个超时间,超过后自动取消操作。

使用context包中的WithDeadline和WithTimeout方法可以实现这个解决方法。先看如下例子:

package mainimport ("context""fmt""time"
)func main() {ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)defer cancel()select {case <-time.After(1 * time.Second):fmt.Println("overslept")case <-ctx.Done():fmt.Println(ctx.Err()) // 输出 "context deadline exceeded"}
}

因为设置的超时时间是50毫秒,所以select会进入第二个case,会输出“context deadline exceeded”。

Golang的net/http包发起http请求的时候是实现了超时控制的,看如下代码:

package mainimport ("context""io""log""net/http""time"
)func main() {req, err := http.NewRequest(http.MethodGet, "https://www.baidu.com", nil)if err != nil {log.Fatal(err)}// 构造一个超时间为50毫秒的Contextctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)defer cancel()req = req.WithContext(ctx)c := &http.Client{}res, err := c.Do(req)if err != nil {log.Fatal(err)}defer res.Body.Close()out, err := io.ReadAll(res.Body)if err != nil {log.Fatal(err)}log.Println(string(out))
}

执行后会输出“context deadline exceeded”,如果将context.WithTimeout方法的timeout参数调大一些,就可以看到正常的返回数据。

上下文传递数据

这个作用在链路追踪中非常重要,链路追踪需要将traceID层层往下传递,在服务间传递。

type traceIdKey struct{}{}// 定义固定的Key
var TraceIdKey = traceIdKey{}func ServeHTTP(w http.ResponseWriter, req *http.Request){// 首先从请求中获取到traceIDtraceId := getTraceIdFromRequest(req)// 将Key存入Context中ctx := context.WithValue(req.Context(), TraceIdKey, traceId)// 设置超时时间ctx = context.WithTimeout(ctx, time.Second)// 携带traceId发起rpc请求repResp := RequestRPC(ctx, ...)// 携带traceId查询DBdbResp := RequestDB(ctx, ...)// ...
}func RequestRPC(ctx context.Context, ...) interface{} {// 获取traceid,在调用rpc时记录日志traceId, _ := ctx.Value(TraceIdKey)// 发起请求// ...return
}

接收到请求后,通过req获取到traceId并记录到Context中,在调用其他RPC服务和查询DB时,传入构造的Context。在后续代码中,可以通过Context拿到存入的traceId。


http://www.ppmy.cn/news/60996.html

相关文章

基于web的商场商城后台管理系统

该系统用户分为两类&#xff1a;普通员工和管理员。普通员工是指当前系统中的需要对商品和客户的信息进行查询的人。此类用户只能查看自己的信息&#xff0c;以及对商品和客户的信息进行查看。管理员用户可以对自己和他人的信息进行维护&#xff0c;包括对商品入库、销售、库存…

2000-2019年30省研发资本存量(含计算过程和原始数据)

2000-2019年30省份研发资本存量&#xff08;含计算过程和原始数据&#xff09;/2000-2019年30个省市R&D资本存量或研发资本存量数据 1、时间&#xff1a;2000-2019年 2、范围&#xff1a;包括30个省市不含西藏 3、指标&#xff1a;省研发资本存量 4、参考文献&#xff…

现代CMake高级教程 - 第 8 章:跨平台与编译器

双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记 第 8 章&#xff1a;跨平台与编译器 在 CMake 中给 .cpp 定义一个宏 #include <cstdio>int main() { #ifdef MY_MACROprintf("MY_MACRO defined! value: %d\n", MY_MACRO); #elseprintf("MY_MACR…

TS2322错误解决方案

废话 之前写C#&#xff0c;所以使用强类型的语言比较习惯&#xff0c;用js觉得有些自由散漫了&#xff0c;所以学习学习ts,结果感觉ts也有好多坑&#xff0c;好多限制&#xff0c;但是又不想使用ts-ingore。多少有点强迫症吧 从网上找了好久都没找到方法。以下方法不一定是主…

【JavaEE】CSS基础知识

文章目录 1.CSS概念1.1CSS是干啥的&#xff1f;1.2基础语法规范1.2基础语法规范1.3引入格式✨内部样式表✨行内样式表✨外部样式&#xff08;最常用的样式&#xff09; 1.4代码风格✨样式格式✨样式大小写 2.选择器2.1选择器的功能2.2基础选择器有哪些&#xff1f;&#x1f6e0…

携手中国电信打造 5G 智慧机场, ALVA Systems 创新 AR 应用闪耀云生态成果展

4 月 26 日&#xff0c;由国家网信办、国家发改委、科技部、工信部、国务院国资委、福建省人民政府共同主办&#xff0c;福州市人民政府等有关单位承办的第六届数字中国建设峰会数字福州暨生态大会在福州举办。 作为数字中国建设主力军之一&#xff0c;中国电信天翼云重磅亮相&…

解决电脑由于找不到vcruntime140_1.dll,无法继续执行代码的方法

vcruntime140_1.dll是微软Visual C程序的运行库文件之一。它包含一些程序所需的函数和其他重要数据&#xff0c;这些程序通常是用Visual C编写的。如果缺少这个文件&#xff0c;可能会导致一些程序无法正常运行&#xff0c;电脑提示vcruntime140_1.dll无法继续执行代码&#xf…

【花雕学AI】我们如何才能避免被ChatGPT替代?——一个跨学科的视角

ChatGPT是一个由OpenAI开发的AI文本工具&#xff0c;它可以理解和生成自然语言&#xff0c;从而与用户进行对话。ChatGPT是基于GPT-3或者GPT-4模型的&#xff0c;这是目前最大和最先进的语言模型之一。ChatGPT通过在大量的互联网文本数据上进行预训练和强化学习&#xff0c;学习…