Posted on May 13, 2019
| 3 minutes
| 568 words
| appleboy
大家在初學 Go 語言時,肯定很少用到 Go Channel,也不太確定使用的時機點,其實在官方 Blog 有提供一篇不錯的文章『Go Concurrency Patterns: Pipelines and cancellation』,相信大家剛跨入學習新語言時,不會馬上看 Go Channel,底下我來用一個簡單的例子來說明如何使用 Go Channel,使用情境非常簡單,就是假設今天要同時處理 20 個背景工作,一定想到要使用 Goroutines,但是又想要收到這 20 個 JOB 處理的結果,並顯示在畫面上,如果其中一個 Job 失敗,就跳出 main 函式,當然又會希望這 20 個 JOB 預期在一分鐘內執行結束,如果超過一分鐘,也是一樣跳出 main 函式。針對這個問題,我們可以整理需要三個 Channel + 一個 Timeout 機制。
fori:=0;i<20;i++{gofunc(outChanchan<-int,errChanchan<-error,valint,wg*sync.WaitGroup){deferwg.Done()time.Sleep(time.Duration(rand.Int31n(1000))*time.Millisecond)fmt.Println("finished job id:",val)outChan<-valifval==11{errChan<-errors.New("error in 60")}}(outChan,errChan,i,&wg)}
宣告 chan<- int 代表在 go func 只能將訊息丟到通道內,而不能讀取通道。
心得
希望透過上述簡單的例子,讓大家初學 Go 的時候有個基礎的理解。用法其實不難,但是請參考專案內容特性來決定如何使用 Channel,最後附上完整的程式碼:
packagemainimport("errors""fmt""math/rand""sync""time")funcmain(){outChan:=make(chanint)errChan:=make(chanerror)finishChan:=make(chanstruct{})wg:=sync.WaitGroup{}wg.Add(100)fori:=0;i<100;i++{gofunc(outChanchan<-int,errChanchan<-error,valint,wg*sync.WaitGroup){deferwg.Done()time.Sleep(time.Duration(rand.Int31n(1000))*time.Millisecond)fmt.Println("finished job id:",val)outChan<-valifval==60{errChan<-errors.New("error in 60")}}(outChan,errChan,i,&wg)}gofunc(){wg.Wait()fmt.Println("finish all job")close(finishChan)}()Loop:for{select{caseval:=<-outChan:fmt.Println("finished:",val)caseerr:=<-errChan:fmt.Println("error:",err)breakLoopcase<-finishChan:breakLoopcase<-time.After(100000*time.Millisecond):breakLoop}}}