這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
package mainimport ( "fmt")func main() { ch := make(chan int) /* 下面2行不能互換,主程式順序執行,若先遇到 ch<-2,則在此阻塞了。程式不會向下執行 */ go f1(ch) //開啟一個協程 ch <- 2 //向channel中傳送資料}func f1(ch chan int) { fmt.Println(<-ch) //輸出資料}
如果容量大於 0,通道就是非同步了:緩衝滿載(發送)或變空(接收)之前通訊不會阻塞,元素會按照發送的順序被接收。如果容量是0或者未設定,通訊僅在收發雙方準備好的情況下才可以成功。
要在首要位置使用無緩衝通道來設計演算法,只在不確定的情況下使用緩衝。
package mainimport ( "fmt")func main() { const N int = 10 data := []int{34, 23, 45, 23, 5, 2, 1, 456, 76, 46} //10個元素 ch := make(chan int) for index, v := range data { go func(index, v int) { ch <- v fmt.Printf("index is %d,value is %d \n", index, v) }(index, v) } for i := 0; i < N; i++ { fmt.Println(<-ch) }}
輸出結果為
index is 0,value is 34
34
23
45
23
5
2
1
456
76
46
解釋:
程式線性執行到第一個for迴圈時,for迴圈內的goroutine開始並發執行(即重開協程執行),10次迴圈結束後,開啟了10個並發的協程(比線程更輕量的概念),而主程式相當於跑了10次空迴圈。
一方面,主線程執行下一個for迴圈,一方面那10個協程並發執行。
主線程當遇到第一個fmt.Println(<-ch) 時,查看channel中是否有值,若有值則讀取並輸出,無值則等待阻塞。
goroutine的協程執行內嵌函數,ch <- v 向channel中傳值,若無線程接受則會阻塞。由於主線程的第二個for有接收值,當主線程接收完值後程式退出。由結果可見協程中的輸出語句只列印了一條(0-n,隨機),因為主程式接收完N個channel值就會退出,而列印語句在協程中處於傳值後。
然後我們看下一個例子,只是在channel建立時指定了大小,channel就成了有緩衝的channel。
package mainimport ( "fmt")func main() { const N int = 10 data := []int{34, 23, 45, 23, 5, 2, 1, 456, 76, 46} ch := make(chan int, N) for index, v := range data { go func(index, v int) { ch <- v fmt.Printf("index is %d,value is %d \n", index, v) }(index, v) } for i := 0; i < N; i++ { fmt.Println(<-ch) }}
輸出結果:
index is 0,value is 34
index is 1,value is 23
index is 2,value is 45
index is 3,value is 23
index is 4,value is 5
index is 5,value is 2
index is 6,value is 1
index is 7,value is 456
index is 8,value is 76
index is 9,value is 46
34
23
45
23
5
2
1
456
76
46
僅僅將channel變為有緩衝結果就變了,因為寫的線程有10個,而讀的線程只有一個(主線程)。寫的速度比讀的快。當是無緩衝時,情況是讀完一個寫一個。有緩衝時,不必等讀,直接可以寫入緩衝,