golang在1.7加入context包加入,网上搜了一下,有很多文章介绍如何用。但本人愚钝,完全不知所以然,于是乎半摸黑的玩了一下,终于弄清楚,这东西究竟是个啥。
context英文翻译为“环境,上下文”,乍一看,完全不知啥意思。上下文?你说程序上下文?这个跟goroutine好像没半毛钱关系。我们知道golang加这个东西,其实为了让goroutine可以控制的啊。
众所周知,“上下文”也算是一些开发术语,不过我觉得,我还真的不懂这究竟是个啥意思,用来装13或许可以感觉上比较牛逼。
说回golang吧,我的理解是,context包唯一的作用就是一个goroutine的开关!为啥这么说?
先上代码:
go func(){
for {
// 一段逻辑
}
}()
上面很简单,就是开一个goroutine,然后跑一个死循环。问题来了,怎么才能控制这个goroutine?试想别的语言,例如c#,好歹开线程,还会返回线程的对象,如果想强行掐断线程,直接调用对象的方法。那golang呢?golang是不行的,因为go是关键字,不会返回任何东西,那么想掐断goroutine,只能用土方法了。
go func(){
for {
if stop {
break
}
}
}
上面可以看出,其实掐断goroutine,就是停掉for循环,就是加一个标志位,然后在外部某个地方再设置一下这个值。那么这样行吗?可以行,但不够简便,因为设置这个标志位,还得枷锁,或者用chan来做。
于是乎,go引入context,作用跟上面其实是一个道理,但因为context实例是线程安全的,就不用考虑枷锁问题。
func main() { ctx, cancel := context.WithCancel(context.Background()) go func() { for { select { case <-ctx.Done(): return default: //TODO: 一些逻辑 } } }() for { time.Sleep(time.Second) cancel() break } i := 0 for { i++ } }
上面代码,就是context的简单使用,context.WithCancel(context.Background())会返回一个context,以及cancel函数,context作用就是插入goroutine中的,如果ctx.Done()有信号,那么就执行return,以达到掐断goroutine的目的。那什么时候ctx.Done触发呢?那就要看cancel函数什么时候被调用了。其实cancel函数被调用,ctx.Done就被触发。上面例子,就是简单的让主goroutine“睡1秒”,就调用cancel(),那么就是过了1秒后,之前创建的goroutine里面的ctx.Done就有信号了,goroutine退出。
看样子好像比标志位复杂了一点,但是context是线程安全的,那么可以传进任意goroutine里面,假如有多个这样的goroutine,那么cancel就是一个总开关,可以一口气把多个goroutine停掉,这是不是很爽?比标志位爽多了,少了各种的锁什么的。
以上,就是本人为啥说context其实是一个开关的原因了。本文其实是简单说了context的其中一种作用,以此抛砖引玉。