序
这是Go标准库中的包之一,优雅、功能强大、编写良好且文档齐全。大多数Go开发者的初级阶段都觉得它更令人困惑,就像我在学习Go程序的早期阶段所遇到的那样,迷茫不知道如何上手。
原理
如下图所示:
Golang 中context
的入口点是上下文包,它是一个根节点emptyCtx
,我们需要的任何上下文(Context
)都将是根(emptyCtx
)上下文的子级。
当需要带有cancel - cancelCtx的上下文时,它实际上会采用父级上下文(空Context
),在本例中context.Background()
返回的就是一个emptyCtx
,并且它将生成以context.Background()
作为父级上下文的新上下文,所以我们可以从先前的上下文创建任何上下文作为父上下文,这样就形成了一个图表,也类似于我们常说的树这种数据结构。
如果父级上下文被取消(cancel
),取消实际上会传播到其所有子级及其子级的所有子级,因此我们在复杂的并发编程中非常有用。
应用
context中有以下几个场景方法:
上面的Background()
与TODO()
都是空上下文,但是一般我们都使用context.Background()
作为根上下文,其余的都是派生上下文
比方说,当你处理某种取消信号时,我们使用带有取消(cancel)的上下文,该函数实际上采用父级上下文,然后返回一个新的上下文和取消函数(
cancel()
),以便我们可以将取消函数用于取消信号ctx := context.Background() // 根节点 ctx, cancel := context.WithCancel(ctx) // 带有取消函数的子级节点
如果我们想设置
Xhr
请求和 go 执行中超时时间,那么我们使用超时(WithTimeout)
和过期时间(WithDeadline)
上下文// WithTimeout ctx := context.Background() ctx, cancle := context.WithTimeout(ctx, 2*time.Second) // 2s 超时 // WithDeadline ctx := context.Background() deadline := time.Now().Add(2*time.Second) // 2s后过期 ctx, cancel := context.WithDeadline(ctx, deadline)
如果在 api 前发送一些请求范围的值,我们可能会使用
WithValue
ctx := context.Background() ctx, cancel := context.WithTimeout(ctx, 2*time.Second) ctx := context.WithValue(ctx, "data", 1) // 设置data为1 fmt.Println(ctx.Value("data").(int)) // 获取data的值
下面我们来看一下context内部的实现:
上图可以看出,context包,Context有四个方法,这四个函数的作用如下:Deadline
:返回 context 是否会被取消以及自动取消时间(即 deadline)Done
: 当 context 被取消或者到了 deadline,返回一个被关闭的 channelErr
: 在 channel Done 关闭后,返回 context 取消原因Value
: 返回与特定键关联的值,当想在上下文获取存在一个指定key的值的时候可以通过ctx.Value("key")
方法去获取
上面这个四个方法都是幂等的。也就是说连续多次调用同一个方法,得到的结果都是相同的。
至此context的简单介绍就道理。后面在去说明context里面的具体实现。