GoLang - Channels
在這幾篇,會以 Go 語言的入門基礎進行逐步說明,本篇針對 Channel 進行說明
前面我們提到關於 gorotuine ,雖然 goroutine 提供了共用記憶體資料的功能,但是在 goroutine 之間還是會透過 channel 來進行通訊。
Go 語言的 channel 具有以下特性:
- 具有線程安全 不需加鎖,多線程操作同一個 channel 不會造成資源競爭
- 只能存放指定型別的數據
- 可用於 goroutine 之間的溝通渠道
- 先進先出(FIFO)
- 包括阻塞(blocking) 及非阻塞(unblocking)
- channel 放滿了就無法在放入數據
- 若從 channel 取出數據,就可在繼續放入
- 沒有使用 goroutine 情況,數據讀取完畢若在讀取,會報出dead lock
接下來,我們會針對 channel 以及他的 buffered/unbuffered 特性來進行說明。
UnBuffered Channel:
go 語言的 channel 預設就是屬於 unbuffered channel,因此,channel在接收跟發送資料過程都是阻塞。
簡單來說,當 channel 接收到值,就會停止在讀取數據,直到 channel 數據被讀取出去,才能再次接收數據。
從另一方面,當 channel 還未有值就被讀取時,會先呈現 blocking 狀態,直到有值傳入 channel 中,才會順利完成讀取動作。
package main
import (
"fmt"
)
func addData(ch chan int) {
ch <- 1
}
func main() {
c := make(chan int)
go addData(c)
fmt.Println(<-c)
}
//output 1
使用 range loop 來操作
在這裡,我們透過 interface{} 來帶入任意型別數值,並且在生產端執行 close() 將 channel 關閉,被關閉的 channel 就無法再發送資料。這時,就可以透過 range 來操作 channel,將數據取出。
func addData(ch chan interface{}) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func main() {
c := make(chan interface{})
go addData(c)
for v := ruang c {
fmt.Println(v)
}
}
//output 0 1 2 3 4 5 6 7 8 9
Buffered Channels:
Go 的 Buffered channels 意思是將 channel 設定緩衝值,例如設定為 5 表示 channel 可以緩衝儲存 5 個元素,指定方式如下:
ch = make(chan type, num) //num 就表示為緩衝值
例如,在這裡我們指定緩衝為 2 ,則可以在 channels 陸續塞入2 個緩衝元素。
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
若將緩衝修改為 1,則會出現錯誤訊息:
fatal error: all goroutines are asleep - deadlock