# golang channel 以下列例子假設 pump 為生產者 , suck 為消費者,假設消費者 先執行的話則有可能 會阻塞, 所以預設buffer 為2的情況下,可以看到我們可以在suck fucntion 透過按下 enter passue 繼續執行 可以看到buffer 永遠會先有值,則 suck 不會發生阻塞, ![](https://i.imgur.com/nhOJSBz.png) 這樣我們的程式就不會阻塞,可以嘗試更改 buffer 為1 or 0 則有可能出現suck 嘗試讀取卻發現buffer 沒有值,則發生死鎖,因為按下enter 的當下suck 先執行發現沒人傳送則阻塞,再換pump 假設又發現沒人接收 則阻塞 1)對於同一個通道,發送操作(協程或者函數中的),在接收者準備好之前是阻塞的:如果ch中的數據無 人接收,就無法再給通道傳入其他數據:新的輸入無法在通道非空的情況下傳入。所以發送操作會等待 ch 再次變為可用狀態:就是通道值被接收時(可以傳入變量)。 2)對於同一個通道,接收操作是阻塞的(協程或函數中的),直到發送者可用:如果通道中沒有數據,接 收者就阻塞了。 ```go= func main() { ch1 := make(chan int, 2) go pump(ch1) // pump hangs // time.Sleep(1 * time.Second) go suck(ch1) http.ListenAndServe(":8080", nil) } func pump(ch chan int) { // time.Sleep(1 * time.Second) fmt.Println("12312") for i := 0; i < 10; i++ { ch <- i fmt.Println("chanel:", len(ch)) } fmt.Println("finsh") } func suck(ch chan int) { // time.Sleep(1 * time.Second) fmt.Println("1231") i := 0 for i < 1 { if len(ch) > 1 { i = 1 } fmt.Println("pause") fmt.Scanln() } for { fmt.Println("chanel2:", len(ch)) fmt.Println(<-ch) } fmt.Println("finsh2") } ``` # 有緩衝 在緩衝區為1的情況下,buffer預存一個int ,suck 則會一直讀到沒有緩衝 下一個就代表沒有資料並結束goroutine,沒有好好回收goroutine ![](https://i.imgur.com/Oc3cmyZ.png) ```go= func main (){ ch1 := make(chan int, 1) go pump(ch1) // pump hangs // time.Sleep(2 * time.Second) go suck(ch1) } func pump(ch chan int) { // time.Sleep(1 * time.Second) fmt.Println("pump") for i := 0; i < 10; i++ { fmt.Println("chanel:", len(ch)) ch <- i fmt.Println("buffer %d", i) // prints only 0 // time.Sleep(1 * time.Second) } // fmt.Println(":", len(ch)) fmt.Println("finsh") } func suck(ch chan int) { // time.Sleep(1 * time.Second) fmt.Println("suck") for { fmt.Println("chanel2:", len(ch)) if len(ch) == 0 { break } fmt.Println(<-ch) fmt.Println("pause") fmt.Scanln() // fmt.Println(":", len(ch)) } fmt.Println("finsh2") } ``` # 監控 gorutine runtime.NumGoroutine() 其他profting https://studygolang.com/articles/14410 main fucntion 可以延遲久一點 看最後存活的nowgoroutine 有幾個 ```go= func main() { largePool = make(chan struct{}, 2) smallPool = make(chan struct{}, 10) ch1 := make(chan int, 1) fmt.Println("first nowgoroutine :", runtime.NumGoroutine()) go pump(ch1) // pump hangs fmt.Println("pump nowgoroutine :", runtime.NumGoroutine()) // time.Sleep(2 * time.Second) go suck(ch1) fmt.Println("suck nowgoroutine :", runtime.NumGoroutine()) // for { // } // fmt.Println(<-ch1) // prints only 0 time.Sleep(10 * time.Second) fmt.Println("all nowgoroutine :", runtime.NumGoroutine()) } func pump(ch chan int) { // time.Sleep(1 * time.Second) fmt.Println("pump") for i := 0; i < 10; i++ { fmt.Println("chanel:", len(ch)) ch <- i fmt.Println("buffer %d", i) // prints only 0 } fmt.Println("finsh") } func suck(ch chan int) { // time.Sleep(1 * time.Second) fmt.Println("suck") for { fmt.Println("chanel2:", len(ch)) fmt.Println(<-ch) fmt.Println("pause") fmt.Scanln() if len(ch) == 0 { break } } fmt.Println("finsh2") } ``` 好的程式設計應該可以讓程式最後結束 gorutine 為可控,不像可控thread 可能會有 resource leak的問題 ![](https://i.imgur.com/RaqhGS8.png) # WaitGroup 這邊有點像操作系統 切換 process or thread ,單核心要切換 process or thread 則還是在同一個核心上 假設有多核心則可以看到process or thread 可以同時run 再多核心上實現平行。 runtime.GOMAXPROCS(1) ![](https://i.imgur.com/9BDgpQk.png) runtime.GOMAXPROCS(2) ![](https://i.imgur.com/A26MGrh.png) ```go= func main(){ runtime.GOMAXPROCS(1) // wg is used to wait for the program to finish. // Add a count of two, one for each goroutine. var wg sync.WaitGroup wg.Add(2) fmt.Println("Start Goroutines") fmt.Println("first nowgoroutine :", runtime.NumGoroutine()) // Declare an anonymous function and create a goroutine. go func() { // Schedule the call to Done to tell main we are done. defer wg.Done() // Display the alphabet three times. for count := 0; count < 3; count++ { for char := 'a'; char < 'a'+26; char++ { fmt.Printf("%c ", char) } } }() fmt.Println("sec nowgoroutine :", runtime.NumGoroutine()) // Declare an anonymous function and create a goroutine. go func() { // Schedule the call to Done to tell main we are done. defer wg.Done() // Display the alphabet three times. for count := 0; count < 3; count++ { for char := 'A'; char < 'A'+26; char++ { fmt.Printf("%c ", char) } } }() // Wait for the goroutines to finish. fmt.Println("Waiting To Finish") fmt.Println("all nowgoroutine :", runtime.NumGoroutine()) wg.Wait() fmt.Println("all nowgoroutine :", runtime.NumGoroutine()) fmt.Println("\nTerminating Program") } ```