前言
在Go的各种框架中,总是能看见context的身影,它被用来进行数据传递、超时通知等。
context在Golang1.7的版本被引入,它被称为协程的上下文,用来在各个协程之间进行上下文信息传递,例如:取消信号、超时信号、数据传递等。这种传递不仅只传送给被调用者、context能够进行链式的调用。
context接口
context被定义为一个接口,只有4个方法
1 | type Context interface { |
- Deadline:用于获得截止时间,当ok为true时,当到达deadline的时间点时,Context会自动发起取消请求,如果ok为false,则不会自动调用。
- Done:该方法只返回一个只读的通道,同时它是无缓冲的通道,Context中也没有任何地方对他写入数据。因此当parent context要取消请求时,会关闭该通道,因为通道的特性,该通道就变成非读堵塞了。接受到done的信号后就可以进行情理操作。
- Err:该方法返回取消的原因,如果Done方法的通道已被关闭就会返回对应的error,否则返回nil
- Value:用于存储键值对的方法
Context类型
emptyContext
这只是一个空的Context,用做初始的的context,即父context。我们通常使用context.Background()
返回该emptyContext类型
1 | type emptyCtx int |
cancelContext
这是一个用于取消通知的context,通常使用context.WithCancel()
来返回该类型,该方法会返回cancelContext和cancel方法。
1 | func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { |
当我们要关闭该context时,就会调用cancel方法,来通知其对应的子goroutine。
timerContext
该context跟cancelContext很想,只不过它是超时自动取消,通常我们使用context.WithTimeout()
来返回该类型。
1 | func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { |
ValueContext
该context就是用于存放键值对的,我们使用context.withValue()
方法来返回。
1 | func WithValue(parent Context, key, val any) Context { |
使用细节
关于context在平常的开发中需要注意几点
- 官方推荐将context作为方法参数放在第一位,而不是丢进结构体。(不过过多的context也不是太好)
- 如果一个函数方法需要传递context,但目前又不需要用到,就可以使用
context.TODO()
返回的结构体,不要直接传递nil - 同时context是线程安全的,平常使用不用特意加锁