1. 程式人生 > >golang的Context包的使用

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的其中一種作用,以此拋磚引玉。