快速喫透 Golang Channels 使用技巧
Golang 可以通過啓動 goroutines 來併發執行任務。它們可以通過一種名爲 "通道" 的通信媒介相互通信。話不多說,下面我列舉了幾種不同情況下 channel 的使用以及其適用條件,最後總結出一張 channel table,能夠幫助你快速喫透 channel 的所有要點。Let't go!
Nil Channels
如果你像創建普通變量一樣創建一個通道,通道將被初始化爲零值。這裏要提到的另一個重要細節是,通道的發送方和接收方都必須做好通信準備,否則我們將收到一個死鎖錯誤。這可以通過緩衝通道來避免,我們將在後面討論。
// NOTE: Deadlock
func nilChannel() {
var ch chan int
// creating a goroutine and sending value on the channel
go func() {
ch <- 1
}()
fmt.Println(<-ch)
}
如果你在 main 中調用這個函數,你會得到以下錯誤和一些其他信息。
fatal error: all goroutines are asleep - deadlock!
這是因爲我們試圖在往 nil channel 上發送一個值,這是堅決不允許的操作。
Empty Channel
在以下代碼中,我們將收到同樣的死鎖錯誤,因爲我們正試圖在 channel receiver 尚未準備好的通道上發送值。從下面的代碼中可以看到,在接收器創建之前,值就已經在通道上發送了。
// NOTE: Deadlock
func emptyChannel() {
var ch = make(chan int)
ch <- 1
fmt.Println(<-ch)
}
UN Buffered Channel
錯誤的代碼已經夠多了。這次讓我給出一個有效的代碼。在下面的代碼中,我們編寫了與上一個示例相同的代碼,但不是創建一個 nil 通道,而是使用 make 函數創建了一個用默認值初始化的通道。不過,如果在這種情況下沒有接收器,就會錯過結果,但不會產生死鎖錯誤。
// NOTE: send single value through goroutine
func simpleChannel() {
var ch = make(chan int)
go func() {
ch <- 1
}()
// NOTE: if you comment this line. You will not be able to receive the result but code will not crash
fmt.Println(<-ch)
}
Channel 方向
默認情況下通道是雙向的。下面的代碼顯示了一個只能用於發送值的通道。如果我們試圖從中獲取值,就會出錯。
func uniDirectionalChannel() {
// Bidirectional [outside goroutine]
var ch = make(chan int)
go func(ch chan<- int) {
// unidirectinal [within goroutine]
ch <- 1
}(ch)
fmt.Println(<-ch)
}
Buffered Channel
這些通道可以像數組一樣容納多個值,因此在非緩衝通道中,如果我們嘗試在沒有接收器的情況下向其寫入數據,就會出錯,但在緩衝通道中,我們可以向其寫入數據,直到緩衝區滿爲止。當緩衝區已滿時,如果我們嘗試向其中寫入新值,就會出錯。如果我們這裏不註釋該函數的最後一行,就會出現死鎖錯誤,因爲這裏將從空通道讀取數據。
// using buffered channel
func bufferdChannelWithoutLoop() {
var ch = make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
// fmt.Println(<-ch) // NOTE: Deadlock, Reading from empty channel
}
從通道讀取數值還有另一種方法,即使用循環。在前面的示例中,我們逐個讀取數值,但我們也可以通過循環讀取接收通道中的數值,因此每當通道中發送一個新數值時,循環就會迭代,執行完正文中的代碼後,就會等待下一個數值。如果接收器試圖讀取,但通道上已沒有其他值,則會出現同樣的死鎖錯誤。
開發人員的職責是在通道使用後將其關閉,因爲如果接收器試圖讀取已經關閉的通道,就會出現上述死鎖問題。
Channels Table
我們已經討論了通道的所有情況,但怎麼才能快速記住它們呢?別緊張😎,有我在,下表可以作爲快速指南,對照着錶盤一下我們寫的 channel 就能避免出現死鎖,並顯示它們在不同情況下的行爲。
另外,推薦一個非常詳細的講解 channel 的視頻:https://www.youtube.com/watch?v=fCkxKGd6CVQ
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/3MFTD5_FG80fSyHSeZhMuw