go context
这两天在看 Context 的最佳实践,在项目中有用到这个东西,但是又没有实际起作用,只是单纯的作为一个参数传来传去。这篇文章的目的就是学会使用 Context 以及阅读 Context 部分源码实现,还有在使用时需要注意的事项。
Context
Background && TODO
Background 一般都是用来当作树的顶点来使用:
func main() { |
需要注意的是,Background 是永远都不会被取消的,这个我们稍后会看到为什么。
TODO 一般用在不清楚使用哪个 Context 时:
// 假设我们有个函数需要 context 作为参数 |
如果说这时候我们不知道要传给这个函数哪个具体的实参,可以使用 context.TODO
代替,将来有具体的 Contetxt 可以把这个替换掉。
底层实现
在底层这两个其实是同一个东西:
var ( |
既然都说到这了,我们看下源码:
// context 在底层就是一个 interface |
emptyCtx 实现了这个接口,但是与其他 ctx
不同的是,emptyCtx 是不会被 cancel 的,也没有任何的 value 和 deadline。
另一个非常有意思的地方,emptyCtx
其实是 int 的一个别名,官方注释提到不使用 struct 的原因是需要不同的地址,可以动手实验一下:
func printAddr() { |
为什么不能使用相同的地址?
个人认为是为了区分 Background 和 TODO,在源码中我们能看到 emptyCtx 有一个方法叫做 String()
func (e *emptyCtx) String() string {
switch e {
case background:
return "context.Background"
case todo:
return "context.TODO"
}
return "unknown empty Context"
}如果说我们使用
type emptyCtx struct{}
作为 Background 和 TODO 的底层实现,那么在这里打印的时候就会走同一个 case 不能显示正确的输出。至于其他原因暂时没想到。
同样的 WithCancel / WithValue 等在底层对应的结构体都实现了这个接口。
funcName | structName |
---|---|
WithValue() | valueCtx |
WithDeadline() / WithTimeout() | timerCtx |
WithCancel() | cancelCtx |
Background() / TODO() | emptyCtx |
题外话,你看这种方式,像不像之前提到的工厂方法模式,上边表格中的 struct 就是工厂方法子类,如果说我们以后要添加一个新的 ctx 是不影响已存在的内容的,满足了开闭原则。
WithCancel
// A cancelCtx can be canceled. When canceled, it also cancels any children |
看到这里有一把琐其实就明白为什么 context 可以并发访问。
cancelCtx 中还有个非常重要的点就是 cancel
取消当前的 ctx 以及对应的 child。
// 通过 channel 告诉要 cancel 掉这个 ctx |
创建 cancelCtx 过程,源码分析
ctx, cancel := context.WithCancel(context.Background()) |
// 可以看到,如果 parent 传递为 nil 时,直接panic |
// propagateCancel arranges for child to be canceled when parent is. |
然后另外 timerCtx
的实现其实大差不差,增加了时间限制而已。
注意事项
使用 Context 需要注意什么呢?
- 不要自己内嵌
Context
; 取而代之的是显示传递Context
给需要的函数。 - Context 应该作为函数的第一个参数。
- 不要给函数传递 nil 的
Context
,尽管函数没加限制,使用context.TODO
代替。 - 使用 context Value 附加参数时,只对那些请求范围内的参数使用。
最佳实践
参考链接: Go Context Best Practices [1]
使用 context 防止 Goroutine 泄露,来源于 [这里]
package main |
本文标题:go context
文章作者:bqyang
发布时间:2022-02-22
最后更新:2023-04-13
原始链接:https://bqyang.top/2022/language/golang/go-context/
版权声明:The author owns the copyright, please indicate the source reproduced.