context是什么
context是一个Go语言独有的结构,不太好用其他语言的类型做例子,具体的功能需要通过例子来表示
channel和select
在了解context使用方法时,需要先理解channel和select的使用,在这里我不详细解释,大概介绍下他们的作用
channel
channel类似于java里的阻塞队列,是一个优雅的线程安全的工具
想了解他的原理,可以看下我之前发的详解channel
select
select也是go独有的一个东西,他的使用方法类似于switch,但他的输入值只能是channel,如果没有channel可以操作就会被阻塞,有的话就会选择case运行。如果有多个channel可以操作,就随机选择一个运行。如果有default方法的话,即时没有channel可以操作,也不会阻塞,而是直接调用default的方法。
示例
首先协程在运行过程中,它指令没有执行完是不会终止的。也就是说写了一个死循环,协程自己会一直运行下去。那么想要终止协程的话,有三种方法
- 使用全局变量
- 使用select,channel
- 使用context
全局变量是最容易想到的方法,这种方法的问题就是会有线程安全问题,所以需要使用锁。
使用select,channel
func recycle(c <-chan int) {
for true {
select {
case <-c:
fmt.Println("a")
default:
fmt.Println("循环中")
}
}
}
相对于全局变量更优雅,对于协程较少来说,是可以使用的。但是协程如果嵌套协程或者有很多层协程,这个关系会很复杂。
所以最优雅的方式就是使用context,这也就引出了他的一个功能,他可以进行信号传递,可以实现上游取消信号,下游任务自行取消的效果
功能
- 传递key value
- 超时控制
- 主动取消控制
context是一个树形结构,当控制一个节点的时候,意味着他的子节点也会被控制。
例如有一个服务调用超时,应该返回失败的数据,但是子协程还在运行,这是没有必要的,就可以通过context阻止子协程的运行。
使用方法
形象的来说就是把 Context 想象为一条河流流过你的程序,每个方法参数开头都一定要是context