这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
Context 接口
Golang 中的 Context 接口提供了上下文消息传递的能力。
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
Deadline方法返回这个Context对象应该结束的时间,ok表示是否设置返回时间Done方法返回一个只读的chan。当这个chan可以读取时,意味着父级Context已经发起了结束请求。此时应该进行清理操作,退出 goroutine,释放资源Err方法返回错误信息Value方法用于获取Context上绑定的值。Context中变量的存储采用键值对的形式,因此需要传递一个key来获取。取值操作通常是协程安全的。
Context 的继承
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
func Background() Context {
return background
}
func TODO() Context {
return todo
}
Golang 针对 Context 接口提供了两个默认实现的对象。
Background方法返回的Context主要应用于main函数、初始化和测试场景,位于整个Context树的根节点,是顶级ContextTODO方法返回的Context主要在尚不清楚具体应用场景时作为占位符使用(官方文档中指出不建议使用值为nil的Context)
这两个 Context 本质上都是 emptyCtx 类型。是一个没有设置结束时间、不可结束、没有携带任何值的 Context。
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
Context 的继承衍生
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, val interface{}) Context
context 包提供了 With 系列函数用于衍生更多子 Context。这些函数都默认传入一个 Context 对象作为父级 Context,并返回一个衍生出的子 Context 对象(可以视为对父级 Context 的继承)。
WithCancel 函数
WithCancel 函数传递一个父 Context 作为参数,返回子 Context,以及一个取消函数用来结束 Context
WithDeadline 函数
WithDeadline 函数会多传递一个截止时间参数,意味着到了这个时间点,会自动取消 Context。当然在实际使用中也可以提前通过结束函数进行结束。
WithTimeout 函数
WithTimeout 函数表示是超时自动取消。
WithValue 函数
与上述三个函数不同,WithValue 函数返回的是原始父级对象的一个副本,作用是绑定一个键值对数据,这个绑定的数据可以被 Context.Value 方法访问到。
其中,键的类型必须是可比较的,并且不应是 string 类型或其他内置类型。实际使用中应该为键值自定义类型。
Context 使用原则
- 不要在结构体中声明
Context类型的字段,而是将Context对象显式地传递给需要的函数 - 使用
Context作为参数的函数和方法,应当将Context作为第一个参数,且参数命名通常为ctx - 不要传递值为
nil的Context。在不清楚使用场景时使用context.TODO() Context仅用于不同进程、goroutine 之间进行数据传输,而不是用于普通函数之间参数的传递Context对于多个 goroutine 是协程安全的