Channel可以當Goroutine間溝通的管道,使用channel的方法很簡單
先宣告一個channel的變數,基本上channel傳遞資料的型態沒有限制,要傳遞interface也是可以的
channel的寫入與讀取是用<-這個符號來做操作
//把值寫入channel
ch <- "second"
//從channel中讀資料出來
receiver := <-ch
以下面的範例在說明怎麼把chan當參數傳遞與channel在Goroutine中當資料傳遞的角色
func main() {
ch := make(chan string)
go testChannel(ch)
go channelTest(ch)
for {
}
}
func testChannel(ch chan<- string) {
fmt.Println("sender to channel")
ch <- "mdfk2020"
}
func channelTest(ch <-chan string) {
receiver := <-ch
fmt.Println("receiver ", receiver)
}
執行結果
sender to channel
receiver mdfk2020
二者的差異性
func main() {
ch := make(chan string)
ch <- "first"
receiver := <-ch
fmt.Println(receiver)
//fatal error: all goroutines are asleep - deadlock!
}
解決方法
func main() {
ch := make(chan string)
go func() {
ch <- "first"
}()
receiver := <-ch
fmt.Println(receiver)
}
func main() {
ch := make(chan string, 1)
ch <- "first"
receiver := <-ch
fmt.Println(receiver)
//妥妥的~~
}
塞超過設定值,直接噴掉啦
func main() {
ch := make(chan string, 1)
ch <- "first"
ch <- "second"
receiver := <-ch
fmt.Println(receiver)
//fatal error: all goroutines are asleep - deadlock!
}
主要是關閉channel不被寫入,但是還是可以讀取喔
func main() {
ch := make(chan string)
go testChannel(ch)
go channelTest(ch)
for {
}
}
func testChannel(ch chan<- string) {
fmt.Println("sender to channel")
ch <- "mdfk2020"
//把channel關閉
close(ch)
}
func channelTest(ch <-chan string) {
receiver := <-ch
fmt.Println("receiver ", receiver)
}
執行結果,依然讀取的到channel寫入值
sender to channel
receiver mdfk2020
如果我把channel關閉後再寫入會發生什麼事情
func main() {
ch := make(chan string)
go testChannel(ch, "mdfk2020")
go channelTest(ch)
time.Sleep(2 * time.Second)
go testChannel(ch, "GGININDER")
go channelTest(ch)
for {
}
}
func testChannel(ch chan<- string, source string) {
fmt.Println("sender to channel")
ch <- source
close(ch)
}
func channelTest(ch <-chan string) {
receiver := <-ch
fmt.Println("receiver ", receiver)
}
執行結果,第一組正常,第二組的讀寫因為遇到channel close的關閉導致系統噴掉,
sender to channel
receiver mdfk2020
receiver
sender to channel
panic: send on closed channel
channle的close有一個原則,receiver不可以close channel,如果receiver進行close會發生什麼事情呢?
會編譯不過XD,這種錯誤比runtime才噴掉好
invalid argument: ch (variable of type <-chan string) must not be a receive-only channel
以上這種情形就是
在使用Go channel的時候,一個適用的原則是不要從接收端關閉channel,也不要關閉有多個並發發送者的channel。換句話說,如果sender(發送者)只是唯一的sender或者是channel最後一個活躍的發送者,那麼你應該在發送者的goroutine關閉頻道,從而通知receiver(s)(接收者們)已經沒有值可以讀了。維持這條原則將保證永遠不會發生向一個已經關閉的channel發送值或者關閉一個已經關閉的channel。
引用The Channel Closing Principle
如果想用channel的特性去卡住Goroutine的話,其實用waitGroup或是errgroup的Wait()也可以做到,
後面的文章會拿channel的特性去做graceful down的動作