人是一種高併發的物種,細品。golang
對 Go 語言的第一印象就是其原生地支持併發編程,並且使用的是協程,比線程更加輕量。編程
for i := 0; i < 10; i++ { go func(n int) { fmt.Println(n) }(i) }
最近有個項目須要同時調用多個 job,並要等待這些 job 完成以後才能往下執行。併發
最開始,咱們擁有一個執行 job 的方法,而且串行執行全部的 job:函數
func buildJob(name string) { ... } buildJob("A") buildJob("B") buildJob("C")
由於全部 job 是能夠併發執行的,這樣就不用必須等待上一個 job 執行完成後,才能繼續執行其餘 job。咱們可使用 Go 語言的關鍵字 go
來快速啓用一個 goroutine
,下面咱們將併發地執行三個 job:高併發
go buildJob("A") go buildJob("B") go buildJob("C")
怎樣才能知道每一個 job 是否已經完成,這裏可使用 channel
進行通訊,並使用 select
檢查執行結果:post
func buildJob(ch chan error, name string) { var err error ... // build job ch <- err // finnaly, send the result into channel } func build() error { jobCount := 3 errCh := make(err chan error, jobCount) defer close(errCh) // 關閉 channel go buildJob(errCh, "A") go buildJob(errCh, "B") go buildJob(errCh, "C") for { select { case err := <-ch: if err != nil { return err } } jobCount-- if jobCount <= 0 { break } } return nil }
當 job A 執行失敗時,build
方法會 return err
退出,並執行 close(errCh)
。但是此時另外兩個 job B 和 C 可能還沒執行完成,同時也會把結果發給 errCh
,但因爲這個時候 errCh
已經被關閉了,會致使程序退出 panic: send on closed channel
。優化
在給 channel 發送數據的時候,可使用接收數據的第二個值判斷 channel 是否關閉:ui
func buildJob(ch chan error, name string) { var err error ... // build job if _, ok := <-ch; !ok { return } ch <- err // finnaly, send the result into channel } func build() error { jobCount := 3 errCh := make(err chan error, jobCount) defer close(errCh) // 關閉 channel go buildJob(errCh, "A") go buildJob(errCh, "B") go buildJob(errCh, "C") for { select { case err := <-ch: if err != nil { return err } } jobCount-- if jobCount <= 0 { break } } return nil }
Go 併發編程看似只須要一個關鍵字 go
就能夠跑起來一個 goroutine
,但真正實踐中,仍是有須要問題須要去處理的。spa
原文連接:https://k8scat.com/posts/code-with-golang-concurrency/線程