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