10.02-Channel
Channel (頻道) 提供一種方式,供兩個 goroutines 可以互相通信,並彼此同步執行。下列是一個使用 channel 的範例程式:
此程式將會持續印出 "ping"(直到按下 Enter 為止)。一個 channel type (頻道型別) 的表示方式是使用關鍵字 chan
以及接著要傳遞給 channel 的資料之型別(在此例中,我們傳遞字串)。
而 <-
(左箭頭)運算符則用於傳送與接收 channel 的訊息,c <- "ping"
表示送出 "ping"
,而 msg := <- c
表示接收一個訊息,並將訊息儲存於 msg
。fmt
這行也可以寫成:fmt.Println(<-c)
,在此例我們可以移除前面那行。
像這樣使用一個 channel 來同步兩個 two goroutines。當 pinger
試圖想要送出該 channel 上的一筆訊息時,它會持續等待(即所謂的阻塞),直到 printer
已經準備好要接收訊息為止。我們將另一個傳送端加到程式中,看會發生什麼事情。新增如下的函式:
再修改 main
:
這個程式現在會輪流印出 “ping” 跟 “pong”。
Channel Direction
我們可以對一個 channel 型別指定 channel direction 來限制它是要做為傳送或是接收。例如:會將 pinger 的函式特徵值修改如下:
現在 c
只能用來傳送,若企圖對 c 進行接收資料將會導致一個編譯的錯誤,我們一樣可以將 printer 改為如下:
若 channel 沒有方向限制,則是所謂的雙向(bi-directional),可以將一個雙向的 channel 傳遞給一個函式做為只能傳送或只能接收的 channel 使用,反之則不可。
Select
Go 有一個特殊的陳述句,稱為 select
,它的作用與 switch
類似,但只能用在 channels:
這個程式每隔兩秒會輸出一次 “from 1”,而每隔三秒會印出一次 “from 2”。select
會選取第一個已經就緒的 channel 來接收(或傳送)資料。若同時有多個 channels 已經就緒,則隨機選取一個 channel 來進行接收。若沒有任何 channel 已經就緒,則會發生阻塞,直到有任何一個 channel 已經就緒為止。
select
陳述句也很常用來實做計時工作(timeout):
time.After
會建立一個 channel,並在指定的時間週期之後送出它所在的目前時間(我們用不到這個時間,所以這裡不會把時間存到變數)。我們也能指定一個 default
的情況:
若沒有任何 channel 已經就緒,則會進去 default 這個情況。
Buffered Channel
在建立一個 channel 時,也可以傳遞第二個參數給 make 函式:
這樣會建立一個容量為1的 buffered channel(有緩衝的頻道),通常 channel 是同步的,channel 兩端會互相等待彼此已經就緒。不過一個有緩衝的 channel 則是非同步的(asynchronous),在傳送或接收一筆訊息時都不用等待,除非 channel 已經滿了。
Last updated