阅读 147

【Go专题】Context的理解

什么是Context

Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
复制代码

我以前对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用法

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}
复制代码

Goroutine的创建和调用关系是分层级的。 为了实现这种关系,Context结构像一棵树,叶子节点须总是由根节点衍生出来的。

创建Context

  • context.Background() 一般使用此方法

  • context.TODO() 在目前还不清楚要使用的上下文时,或上下文尚不可用时,使用此方法

创建子节点

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 interface{}, val interface{}) Contex
复制代码

使用Context原则

  1. 不要把Context存在一个结构体当中,要显式地传入函数。Context变量需要作为第一个参数使用,一般命名为ctx;
  2. 即使方法允许,也不要传入一个nil的Context。如果你不确定要用什么Context,那么传一个context.TODO
  3. 使用context的Value方法时,只应该在程序和接口中传递“和请求相关的元数据”,不要用它来传递一些可选的参数;
  4. 要养成关闭 Context 的习惯,在建立之后,立即 defer cancel() 是一个好习惯

Q&A

1、如果不使用Context来保证请求处于一个生命周期,是否有其他的方式?

2、对于Context源码分析--->待办

参考资料:

  1. blog.csdn.net/chinawangfe…
  2. golang.google.cn/pkg/context…
文章分类
后端
文章标签