Golang 語言怎麼控制併發 goroutine?
01
介紹
Golang 語言的優勢之一是天生支援併發,我們在 Golang 語言開發中,通常使用的併發控制方式主要有 Channel,WaitGroup 和 Context,本文我們主要介紹一下 Golang 語言中併發控制的這三種方式怎麼使用?關於它們各自的詳細介紹在之前的文章已經介紹過,感興趣的讀者朋友們可以按需翻閱。
02
Channel
在 Golang 語言中,Channel 不僅可以用於協程之間通訊,還可以使用 Channel 控制子協程,而且使用 Channel 實現併發控制比較簡單,比如以下示例,我們在 Golang 應用程式中啟動兩個協程,分別是主協程和子協程,主協程需要等待子協程執行結束後再退出程式。
示例程式碼:
funcmain(){
done:=make(chanstruct{})
gofunc(){
fmt.Println("goroutinerunover")
done<-struct{}{}
}()
<-done
fmt.Println("maingoroutinerunover")
}
閱讀上面這段程式碼,我們在子 goroutine 執行結束後,通過 Channel 通知主 goroutine 退出程式,實際上也可以反過來處理,主 goroutine 通知子 goroutine 退出程式,主 goroutine 向 channel 中傳送資料,子 goroutine 等待接收 channel 中的資料。
03
sync.WaitGroup
如果在 Golang 應用程式中,需要讓主 goroutine 等待多個 goroutine 都執行結束後再退出程式,我們應該怎麼實現呢?是的,同樣可以使用 Channel 實現,但是,有一個更優雅的實現方式,那就是 WaitGroup,顧名思義,WaitGroup 就是等待一組 goroutine 執行結束。
示例程式碼:
funcmain(){
wg:=sync.WaitGroup{}
wg.Add(10)
fori:=0;i<10;i++{
gofunc(idint){
fmt.Println(id,"執行結束")
wg.Done()
}(i)
}
wg.Wait()
fmt.Println("maingoroutinerunover")
}
閱讀上面這段程式碼,我們啟動 10 個子 goroutine,主 goroutine 需要等待 10 個子 goroutine 都執行結束後再退出程式,我們使用的是 WaitGroup,它有三個方法,分別是 Add、Done 和 Wait,實際上 WaitGroup 維護了一個計數器,這三個方法都是圍繞這個計數器工作,Add 用於設定計數器的數值,Done 用於扣減計數器的數值,Wait 在計數器數值為 0 之前一直阻塞。關於 WaitGroup 的原始碼解讀,在之前的文章中已介紹過,限於篇幅,這裡就不再贅述。
04
Context
Channel 和 WaitGroup 通常用於父子兩個層級的 goroutine 的應用程式的併發控制中,如果在 Golang 應用程式中,子協程繼續派生出協程,我們應該怎麼控制呢?這種多級 goroutine 的應用程式,我們可以使用 Context 實現併發控制。
示例程式碼:
funcmain(){
ctx,cancel:=context.WithCancel(context.Background())
gofirstCtx(ctx)
time.Sleep(5*time.Second)
fmt.Println("stopallsubgoroutine")
cancel()
time.Sleep(5*time.Second)
}
funcfirstCtx(ctxcontext.Context){
gosecondCtx(ctx)
for{
select{
case<-ctx.Done():
fmt.Println("firstdone")
return
default:
fmt.Println("firstrunning")
time.Sleep(2*time.Second)
}
}
}
funcsecondCtx(ctxcontext.Context){
for{
select{
case<-ctx.Done():
fmt.Println("seconddone")
return
default:
fmt.Println("secondrunning")
time.Sleep(2*time.Second)
}
}
}
閱讀上面這段程式碼,在子協程 firstCtx 啟動子協程 secondCtx,主 goroutine 建立 context,並把 context 傳遞到所有子協程,然後主 goroutine 通過呼叫 cancle 停掉所有子協程。
05
總結
本文我們介紹了不同場景中分別適合哪種控制併發 goroutine 的方式,其中,channel 適合控制少量 併發 goroutine,WaitGroup 適合控制一組併發 goroutine,而 context 適合控制多級併發 goroutine。