golang的Context包的使用

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的其中一种作用,以此抛砖引玉。

猜你喜欢

转载自blog.csdn.net/gtd138/article/details/81941129