【go 专题】Context 的理解
什么是 Context
我以前对 Context 的理解,就是从字面上理解:上下文,一个请求链路中一直存在的某信息。打个比方,Client 请求 A-Service 到 B-Service,B-Service 再到 C-Service,在这个请求链路中,上游就会将内容传递给下游,A-->B,B--->C 是保持一个请求过程的。Context 是程序单元的一个运行状态、现场、快照。结合这句话,我对 Context 的理解是 Context 用于保证一个 Request 在同一个生命周期内。
在 Go 语言中,程序单元指的就是 Goroutine。
所以,一个 Request,可能会在多个 goroutine 中去处理,多个 goroutine 可能共享 Request 信息,都在同一个生命周期内,如果 Request 请求取消或超时,则所有的 goroutine 都应该结束。
为什么需要 Context
上述刚才说一个请求可能会在多个 goroutine 中去处理,所以如果其中一个 goroutine 超时了或者中断了,那这个 Request 就应该被立即停止结束,而不是一直等待。
所以,每个长请求都应该有个超时限制,一个长请求需要一个 Context 来保证整个请求都是在同一个生命周期内。有点“一荣俱荣,一损俱损”的味道。
使用场景
任何可能被阻塞,或者需要很长时间来完成的,都应该有个 context.Context
rpc 调用
长请求,长链路/多函数调用
Go 中 Context 用法
Goroutine 的创建和调用关系是分层级的。 为了实现这种关系,Context 结构像一棵树,叶子节点须总是由根节点衍生出来的。
创建 Context
context.Background() 一般使用此方法
context.TODO() 在目前还不清楚要使用的上下文时,或上下文尚不可用时,使用此方法
创建子节点
使用 Context 原则
不要把 Context 存在一个结构体当中,要显式地传入函数。Context 变量需要作为第一个参数使用,一般命名为 ctx;
即使方法允许,也不要传入一个 nil 的 Context。如果你不确定要用什么 Context,那么传一个 context.TODO
使用 context 的 Value 方法时,只应该在程序和接口中传递“和请求相关的元数据”,不要用它来传递一些可选的参数;
要养成关闭 Context 的习惯,在建立之后,立即 defer cancel() 是一个好习惯
Q&A
1、如果不使用 Context 来保证请求处于一个生命周期,是否有其他的方式?
2、对于 Context 源码分析--->待办
参考资料:
https://blog.csdn.net/chinawangfei/article/details/86559975
https://golang.google.cn/pkg/context/
版权声明: 本文为 InfoQ 作者【南吕】的原创文章。
原文链接:【http://xie.infoq.cn/article/4040b1f25d742641d1296e846】。
本文遵守【CC BY-NC】协议,转载请保留原文出处及本版权声明。
评论