Golang(五)Context 的使用和源码分析
2023-06-13 09:13:21 时间
0. 前言
- golang 的 Context 包,是专门用来简化对于处理单次请求但是涉及到多个 goroutine 之间与请求域的数据、取消信号、截止时间等相关操作,这些操作可能涉及多个 API 调用
- 常见场景如一个微服务后台,各个 RPC 接口逐个调用形成一个调用链,某一时刻超时,要通知调用链上所有正在调用的请求断开连接
- 这样的话, 我们就可以通过 Context,来跟踪这些 goroutine,并且通过 Context 来控制他们的目的,这就是 Golang 语言为我们提供的 Context,中文可以称之为”上下文“
1. 定义
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
- Context 的主要数据结构是一单向的继承关系的结构
- 根据使用场景的不同,每一层context都具备有一些不同的特性
- 这种层级式的组织也使得 context 易于扩展,职责清晰
- Deadline 方法是获取设置的截止时间的意思
- 第一个返回值为截止时间,即到了这个时间点,Context 会自动发起取消请求
- 第二个返回值为 false 时表示没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消
- Done 方法返回一个只读的chan,类型为 struct{}
- 在 goroutine 中,如果该方法返回的chan可以读取,则意味着 parent context 已经发起了取消请求
- 我们通过 Done 方法收到这个信号后,就应该做清理操作,然后退出 goroutine,释放资源
- 之后,Err 方法会返回一个错误,告知为什么 Context 被取消
- Err 方法返回取消的错误原因,因为什么 Context 被取
- Value 方法获取该 Context 上绑定的值,是一个键值对,所以要通过一个 Key 才可以获取对应的值,这个值一般是线程安全的
2. 基本实现
- Golang 内置的 context 包,已经给出了 Context 的两个实现
- 一般在代码中,开始上下文的时候都是以这两个作为最顶层的 parent context 节点,然后再衍生出子 context
- 这些 Context 对象形成一棵树:当一个 Context 对象被取消时,它的所有子节点都会被取消。两个实现如下:
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
func Background() Context {
return background
}
func TODO() Context {
return todo
}
- Background,主要用于 main 函数、初始化以及测试代码中,作为 Context 这个树结构的最顶层的 Context,但是不能被取消
- TODO,如果我们不知道该使用什么 Context 的时候,可以使用这个而不是传一个空接口
- 他们两个本质上都是 emptyCtx 结构体类型,是一个不可取消,没有设置截止时间,没有携带任何值的 Context
3. 继承和使用
- 通过 With 函数,可以创建 Context 树,树的每个节点都可以有任意多个子节点,节点层级可以有任意多个
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
- WithCancel 函数,传递一个父 Context 作为参数,返回子 Context,以及一个取消函数用来取消 Context
- WithDeadline 函数,相对 WithCancel 多传递一个截止时间参数,意味着到了这个时间点,会自动取消 Context,也可以提前通过取消函数进行取消
- WithTimeout 和 WithDeadline 基本上一样,这个表示是超时自动取消,是多少时间后自动取消 Context 的意思
- WithValue 函数和取消 Context 无关,它是为了生成一个绑定了 key 、value 的数据的Context
- 这个绑定的数据可以通过 Context.Value 方法访问到,这是我们实际用经常要用到的技巧
- 一般我们想要通过上下文来传递数据时,可以通过这个方法
4. 参考文献
相关文章
- Postgresql源码(80)plpgsql中异常处理编译与执行流程分析(sqlstate)
- golang中的map并发读写问题: Golang 协程并发使用 Map 的正确姿势
- 一款在线多张图片拼图工具HTML源码
- Golang的strings.go源码解析 - Rabin-Karp了解一下?
- Java volatile源码分析
- 在线客服系统源码开发实战总结:Golang实现CMS内容管理增删查改功能
- 【说站】语音变声器微信小程序源码_支持多种音效
- Go-Excelize API源码阅读(二十七)——SetRowOutlineLevel、SetColOutlineLevel
- 最像源码的自制版IOC
- 开源在线客服系统源码(支持PC/H5/公众号/小程序)基于golang的网页在线客服系统
- golang源码分析:golang使用mysql XA事务
- golang源码分析:dtm分布式事务(3)
- golang源码分析:grpc 链接池(1)
- golang源码分析:grpc 链接池(2)
- golang源码分析:grpc 链接池(4)自定义resolver 、balancer和picker
- golang源码分析:grpc 链接池(5)自定义组件和框架交互流程
- golang源码分析:http代理和https代理
- golang 源码分析:json格式请求grpc服务的
- golang 源码分析:nacos服务发现
- 在线客服系统源码编译Golang语言下go build命令构建二进制程序
- SpringBoot源码分析系列之一:如何启动内嵌Tomcat
- Golang 上下文 Context 通过案例讲源码(1): 值传递
- 「建议收藏」 十篇文章带你 Golang Cobra 入门到实战(含源码讲解)
- mold源码阅读 其零 main
- Golang流媒体实战之六:lal拉流服务源码阅读
- GEM技术导航系统开心版源码
- 分析Linux LS 命令源码剖析(linuxls源码)
- 快速了解Redis源码的方法(怎样查redis代码)
- 分析深入探讨Redis集中式缓存源码(redis集中式缓存源码)
- 纯C语言:分治快速排序源码分享