专业的编程技术博客社区

网站首页 > 博客文章 正文

理解 Golang 中的上下文包(Context)

baijin 2025-03-30 14:16:18 博客文章 9 ℃ 0 评论

Context:这是Go标准库中最受欢迎的包之一,它优雅、强大、文档齐全,但是大多数Gopher在初始阶段发现它很难理解,这也是我之前学Go早期遇到的问题,所以我想写这篇文章综合我对context包的理解来帮到Gopher。

模拟Context使用的场景

  • 场景一

第一种情况context允许两个协程之间发送取消信息,你家里来了一个朋友,他想吃麦当劳。这意味着他给了你一个任务吃麦当劳,所以你叫了你弟弟去买麦当劳。与此同时,你的朋友现在不想吃麦当劳了,但是你已经叫你弟弟去买了,所以你需要打电话告诉你弟弟告诉他不要去买麦当劳然后回来,因为你不再需要了。

  • 场景二

第二种情况是为任务设置截止日期,假设你十几岁的时候正忙着和你的朋友玩。所以你的父母说如果你在晚上 9 点之后回家,那就别回家来了。

  • 场景三

第三种情况是在请求中连同Context本身一起发送值。

简单理解,Golang 中的应用程序使用context来控制和管理可靠应用程序的非常重要的方面,例如并发编程中的取消和数据共享。

如何使用Context

  1. Golang 中context的入口点是context包,它是根context,其它任何context都将是根context的子项
  2. 每当需要带有 cancel -cancelCtx的context时,它实际上会采用parent context(emptyContext),在这种情况下它是context.Background(),它会生成带有context.Background()作为parent context的new context,所以这意味着可以从以前的context中创建任何context作为parent context。
  3. 如果parent context被取消,取消实际上会传播到它的所有子节点,以及它子节点的所有子节点,所以这在复杂并发执行中非常有用。

  1. 在以上两种情况中,两者都是empty context,使用context.Background()作为根context,其余的都是派生context。
  2. 当你处理某种取消信号时,你会使用context和cancel,这个函数实际上接受父context,然后返回一个新的context和取消函数,这样取消函数就可以用来处理取消信号。

  1. 如果你想在api请求和go协程程序之间带有最后期限,那么就要采用超时和最后期限context

  1. 如果你想在 api 边界之间发送一些请求范围的值,你可能会使用 with values

context的三种情况

  1. 第一个是Deadline func,所以deadline函数在context被取消时帮助我们,如果上下文中没有取消信号,那么它将返回false。
  2. 第二个是Done func,返回在程序结束执行时关闭的通道,因为context已被取消
  3. 第三个是Err函数,它只是返回错误
  4. 第四个是Value函数,它返回键关联的值

运行上面的代码好像没有输出,原因我们在上面的程序中实际上并没有捕获context,上面我们提到context的interface里面有Done()这个方法,因为我们已经分配了done func,所以必须要捕获context cancel的信号才行。

通过使用select来捕获context取消的信号。捕获到取消信号之后输出时间跟错误。

  • 使用超时context的情况

上面的代码我们函数需要3秒的时间来打印“hello”,但是我们在2秒后超时,所有结果是context deadline exceeded

  • 使用deadline的情况

对于withDeadline context,它与withTimeout context相同,如果看到 withTimeout 函数,它实际上在内部调用withDeadline() fun,所以即使调用 withTimeout,实际上也始终在调用withDeadline函数

如果我们设置一个deadline距当前时间2秒,但是我们的函数需要4秒才能响应,程序运行的结果肯定是context deadline exceeded

如果我们设置deadline距当前时间2秒,并添加1秒来执行打印的函数,它如期输出了“hello”

  • contextwithValue的用例
  1. 使用 ctx.value() ,通常是将请求代码值发送到 http 请求
  2. 该场景就像发送附加到context本身的请求ID,这将有助于跟踪我们的请求

服务端代码示例:

客户端代码示例:

代码运行输出结果:

id i 5577006791947779410
2022/09/05 16:56:19 5577006791947779410 -> context canceled

结论

如果正在执行 Web 请求或运行系统命令,则为生产级系统设置超时通常是个好主意。因为,如果依赖的 API 运行缓慢不会希望保存该请求,因为它最终可能会增加负载并降低服务的所有请求的性能。导致级联效应。这就是超时或期限上下文可以派上用场的地方

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表