大家好,我是煎鱼。
上下文(Context)是 Go 语言中非常有特色的一个特性, 在 Go 1.7 版本中正式引入新标准库 context。
其主要的作用是在 goroutine 中进行上下文的传递,而在传递信息中又包含了 goroutine 的运行控制、上下文信息传递等功能。
为加强大家对 Go 语言的 context 的设计,本文将对标准库 context 进行深入剖析,看看他里面到底暗含了何物,又为何能够做那么多事。
整体的描述结构是:“了解 context 特性,熟悉 context 流程,剖析 context 原理” 三个板块进行。目录如下:
什么是 context
Go 语言的独有的功能之一 Context,最常听说开发者说的一句话就是 “函数的第一个形参真的要传 ctx 吗?”,第二句话可能是 “有没有什么办法不传,就能达到传入的效果?”,听起来非常魔幻。
在 Go 语言中 context 作为一个 “一等公民” 的标准库,许多的开源库都一定会对他进行支持,因为标准库 context 的定位是上下文控制。会在跨 goroutine 中进行传播:
本质上 Go 语言是基于 context 来实现和搭建了各类 goroutine 控制的,并且与 select-case
联合,就可以实现进行上下文的截止时间、信号控制、信息传递等跨 goroutine 的操作,是 Go 语言协程的重中之重。
context 基本特性
演示代码:
func main() {
parentCtx := context.Background()
ctx, cancel := context.WithTimeout(parentCtx, 1*time.Millisecond)
defer cancel()
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
}
输出结果:
context deadline exceeded
我们通过调用标准库 context.WithTimeout
方法针对 parentCtx
变量设置了超时时间,并在随后调用 select-case
进行 context.Done
方法的监听,最后由于达到截止时间。因此逻辑上 select
走到了 context.Err
的 case
分支,最终输出 context deadline exceeded
。
除了上述所描述的方法外,标准库 context
还支持下述方法:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
type Context
func Background() Context
func TODO() Context
func WithValue(parent Context, key, val interface{}) Context
WithCancel:基于父级 context,创建一个可以取消的新 context。
WithDeadline:基于父级 context,创建一个具有截止时间(Deadline)的新 context。
WithTimeout:基于父级 context,创建一个具有超时时间(Timeout)的新 context。
Background:创建一个空的 context,一般常用于作为根的父级 context。
TODO:创建一个空的 context,一般用于未确定时的声明使用。
WithValue:基于某个 context 创建并存储对应的上下文信息。
context 本质
我们在基本特性中介