# Go - Goroutine,Channel ###### tags: `Go`,`Goroutine`,`Channel` ## Goroutine、Channel 用途 Goroutine用於平行處理。也就是**非同步執行**。 執行時如果是單線程(Single Thread)的,那麼執行時只會用到一個 CPU,如果你的電腦有兩個以上的 CPU,那可以想辦法讓他們分工合作。 分工合作需要溝通,Channel用途在於可以讓不同的Goroutine去溝通。 ## 如何宣告Channel 搭配make()使用。 ```go= import "fmt" func main(){ s := make(chan string) //宣告一個 channel 變數 s <- "hello" //寫入 channel (sender) val <- s //讀取 channel (receiver) fmt.Println(val) } ``` 分辨讀寫非常容易,請看 <- 符號放在哪邊,**chan<- 指向自己就是寫,<-chan 離開自己就是讀**,相當好分辨,如果 func 內讀寫都需要使用,則不需要使用任何箭頭符號,但是我會建議把讀寫的邏輯都拆開不同的 func 處理,對於閱讀上非常有幫助。 ```go= Write(chan<- int) Read(<-chan int) ReadWrite(chan int) ``` ## 範例 * 任務:加總數字 ```go= func Sum(numbers []int) int { total := 0 for _, n := range numbers { total += n } return total } ``` * 任務:分兩個CPU加總數字 ```go= func SumTwoParallel(numbers []int) int { mid := len(numbers) / 2 ch := make(chan int) go func() { ch <- Sum(numbers[:mid]) }() go func() { ch <- Sum(numbers[mid:]) }() total := <-ch + <-ch return total } //結果 用兩個CPU運算比較快: // > go test -bench=^BenchmarkSumTwoParallel$ // goos: darwin // goarch: amd64 // BenchmarkSumTwoParallel-8 5000 300351 ns/op ``` ## 確認有多少CPU 有多少CPU就全部教叫出來做事,可以使用 `runtime.NumCPU()` 取得 CPU 的數量,再把 slice 切割成 N 等份給不同的 goroutine 去加總,最後再統合到 total,這樣不管跑這段程式的電腦有幾個 CPU 都可以均勻分配。 ```go= func SumMaxParallel(numbers []int) int { nCPU := runtime.NumCPU() nNum := len(numbers) ch := make(chan int) for i := 0; i < nCPU; i++ { from := i * nNum / nCPU to := (i + 1) * nNum / nCPU go func() { ch <- Sum(numbers[from:to]) }() } total := 0 for i := 0; i < nCPU; i++ { total += <-ch } return total } ``` ## 參考資料 https://larrylu.blog/golang-goroutine-parallel-processing- https://blog.wu-boy.com/2020/01/when-to-use-go-channel-and-goroutine/