本篇要跟大家聊聊在 Go 語言內什麼是『unbuffered vs buffered channel』,在初學 Go 語言時,最大的挑戰就是了解 Channel 的使用時機及差異,而 Channel 又分為兩種,一種是 buffered channel,另一種是 unbuffered channel,底下我來用幾個簡單的例子帶大家了解這兩種 channel 的差異,讓初學者可以很快的了解 channel 使用方式。
教學影片
直接看影片比較快,五分鐘左右就可以初學了解 channel
- 00:22 unbuffered channel
- 02:32 buffered channel
更多實戰影片可以參考我的 Udemy 教學系列
- Go 語言實戰課程: http://bit.ly/golang-2019
- Drone CI/CD 自動化課程: http://bit.ly/drone-2019d
Unbuffered Channel
在 Go 語言內使用 goroutine 是很常見的,但是我們該如何透過 Channel 來解決同步問題,請看底下例子
func main() {
go func() {
fmt.Println("GO GO GO")
}()
time.Sleep(1 * time.Second)
}
上面的例子在執行完 main 函數,就會直接跳出,所以後面設定了等待一秒可以解決此問題,但是一班開發模式不會加上 Timeout,這邊該如何透過 Unbuffered Channel 方式來達到一樣的效果。
func main() {
c := make(chan bool)
go func() {
fmt.Println("GO GO GO")
c <- true
}()
<-c
}
可以看到上面我用了 make(chan bool) 來建立一個 channel,當在 main 函數最後用 <-c 代表需要等待讀出一個 channel 值,main 函數才會結束,這時候就達到了跟用 Sleep 一樣的效果,接著將程式碼改成如下:
func main() {
c := make(chan bool)
go func() {
fmt.Println("GO GO GO")
<-c
}()
c <- true
}
你會發現得到同樣的結果,為什麼呢?因為 unbufferd channel 的用途就是,今天在程式碼內丟了一個值進去 channel,這時候 main 函式就需要等到一個 channel 值被讀出來才會結束,所以不管你在 goroutine 內讀或寫,main 都需要等到一個寫一個讀完成後才會結束程式。這就是用 unbuffered channel 來達到同步的效果,也就是保證讀寫都需要執行完畢才可以結束主程式。
buffered Channel
那 buffered Channel 呢,差異在於宣告方式,請看底下例子
func main() {
c := make(chan bool, 1)
go func() {
fmt.Println("GO GO GO")
<-c
}()
c <- true
}
可以很清楚知道 buffered channel 是透過 make(chan bool, 1) 後面有帶容量值,開發者可以一次宣告此 channel 可以容納幾個值,大家可以執行看看上述程式碼,會發現完全沒有輸出東西,原因是什麼,buffered channel 就是只要容量有多少,你都可以一直塞值進去,但是不用讀出來沒關係,所以當丟了 c <- true 進去後,主程式不會等到讀出來才結束,造成使用者沒有看到 fmt.Println("GO GO GO"),這就是最大的差異。
結論
大家記住 unbuffered channel 就是代表在主程式內,需要等到讀或寫都完成,main 才可以完整結束,而 buffered channel 相反,你可以一直丟資料進去 Channel 內,但是不需要讀出來,所以 main 才提前結束。如果您想要用 channel 做到同步或異步的效果,這邊就需要注意了。希望本邊有幫助到大家初學 Channel。之後會有更多深入的文章來講解 Channel,如果要看更多 Go 影片可以參考這邊。