Go - Channels
Go - Channels
September 23, 2024
Channel
Channel 是個 typed 的管道,go 程式可以透過 channel operator <-
去接受或發送某個值。透過 channel 可以同步不同的 Goroutine。
箭頭的方向就代表了資料的傳輸方向:
ch := make(chan int) // create a channel for int
v := 100
go func() {
fmt.Println("Sending v to channel")
ch <- v // Send value to the channel
}()
recv := <- ch // Get value from the channel
fmt.Printf("recv: %v", recv)
預設情況下,接受與發送都會 block 住,直到另一端也發送或接受,像是以下的程式會停在 ch <- v
,因為程式還在等人發送值到 channel 中,會出現 deadlock 錯誤 fatal error: all goroutines are asleep - deadlock!
:
ch := make(chan int) // create a channel for int
v := 100
fmt.Println("Sending v to channel")
ch <- v // The code will stop here and wait for the value...
recv := <- ch
fmt.Printf("recv: %v", recv)
channel 的 block 行為是可以被控制的,channel 可以宣告成 buffered channel,一個 buffered channel 裡的值可以保存起來,接受端只要拿的到值就可以繼續,發送端只要發送值進去後 channel 沒有超過容量也可以繼續。
buffered channel 的容量透過 make()
的第二個參數指定:
ch := make(chan int, 1)
將上面會造成 deadlock 的 channel 改成 buffered channel (size = 1) ,就可以正常執行了:
ch := make(chan int, 1) // create a buffered channel for int
v := 100
fmt.Println("Sending v to channel")
ch <- v
recv := <- ch
fmt.Printf("recv: %v", recv)
Close the channel
- Sender 可以透過
close(channel)
通知 receiver 之後不會傳東西到這個 channel 中了。 - Receiver 可以透過
v, ok := <- ch
的ok
是false
得知 channel 已被關閉,也可以透過for i := range c
接受值,直到 channel 被關閉。
Select
select
可以從多個 case 中執行符合的操作。- 如果同時有多個條件都符合,隨機選一個。
select
(在沒有定義default
時),會 block 並等待某個 case 並執行對應的操作:select
加上default
後就不會 block,因為當其他 channel 都還沒好時,會進到default
中,見官方範例參考:
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}