如果說goroutine是Go語言程序的并發(fā)體的話,那么channels則是它們之間的通信機制。一個channel是一個通信機制,它可以讓一個goroutine通過它給另一個goroutine發(fā)送值信息。
1 創(chuàng)建channel
每個channel都有一個特殊的類型,也就是channels可發(fā)送數(shù)據(jù)的類型。一個可以發(fā)送int類型數(shù)據(jù)
的channel一般寫為chan int。使用內置的make函數(shù),如果第二個參數(shù)大于0,則表示創(chuàng)建一個帶緩存的channel。
ch := make(chan int) // ch has type 'chan int'
ch = make(chan int, 3) // buffered channel with capacity 3
2 channel的發(fā)送和接受
一個發(fā)送語句將一個值從一個goroutine通過channel發(fā)送到另一個執(zhí)行接收操作的goroutine。發(fā)送和接收兩個操作都使用-運算符。在發(fā)送語句中,-運算符分割channel和要發(fā)送的值。在接收語句中,-運算符寫在channel對象之前。一個不使用接收結果的接收操作也是合法的。
ch - x
// a send statement
x = -ch // a receive expression in an assignment statement
-ch
// a receive statement; result is discarded
3 channel的close
Channel還支持close操作,用于關閉channel,隨后對基于該channel的任何發(fā)送操作都將導致panic異常。對一個已經被close過的channel進行接收操作依然可以接受到之前已經成功發(fā)送的數(shù)據(jù),如果channel中已經沒有數(shù)據(jù)的話將產生一個零值的數(shù)據(jù)。使用內置的close函數(shù)就可以關閉一個channel:
4 不帶緩存的Channels
一個基于無緩存Channels的發(fā)送操作將導致發(fā)送者goroutine阻塞,直到另一個goroutine在相同的Channels上執(zhí)行接收操作,當發(fā)送的值通過Channels成功傳輸之后,兩個goroutine可以繼續(xù)執(zhí)行后面的語句。反之,如果接收操作先發(fā)生,那么接收者goroutine也將阻塞,直到有另一個goroutine在相同的Channels上執(zhí)行發(fā)送操作。
基于無緩存Channels的發(fā)送和接收操作將導致兩個goroutine做一次同步操作。因為這個原因,無緩存Channels有時候也被稱為同步Channels。
5 串聯(lián)的Channels
Channels也可以用于將多個goroutine連接在一起,一個Channel的輸出作為下一個Channel的輸入。這種串聯(lián)的Channels就是所謂的管道(pipeline)。
func main() {
naturals := make(chan int)
squares := make(chan int)
// Counter
go func() {
for x := 0; x 100; x++ {
naturals - x
}
close(naturals)
}()
// Squarer
go func() {
for x := range naturals {
squares - x * x
}
close(squares)
}()
// Printer (in main goroutine)
for x := range squares {
fmt.Println(x)
}
}
當一個被關閉的channel中已經發(fā)送的數(shù)據(jù)都被成功接收后,后續(xù)的接收操作將不再阻塞,它們會立即返回一個零值。
Go語言的range循環(huán)可直接在channels上面迭代。使用range循環(huán)依次從channel接收數(shù)據(jù),當channel被關閉并且沒有值可接收時跳出循環(huán)。
6 單方向的Channels
為了防止被濫用,Go語言的類型系統(tǒng)提供了單方向的channel類型,分別用于只發(fā)送或只接收的channel。類型-chan int表示一個只接收int的channel, chan- int表示一個只發(fā)送int的channel,(箭頭-和關鍵字chan的相對位置表明了channel的方向。),這種限制將在編譯期檢測。
func counter(out chan- int) {
for x := 0; x 100; x++ {
out - x
}
close(out)
}
func squarer(out chan- int, in -chan int) {
for v := range in {
out - v * v
}
close(out)
}
func printer(in -chan int) {
for v := range in {
fmt.Println(v)
}
}
func main() {
naturals := make(chan int)
squares := make(chan int)
go counter(naturals)
go squarer(squares, naturals)
printer(squares)
}
7 帶緩存的Channels
帶緩存的Channel內部持有一個元素隊列。隊列的最大容量是在調用make函數(shù)創(chuàng)建channel時通過第二個參數(shù)指定的。
向緩存Channel的發(fā)送操作就是向內部緩存隊列的尾部插入元素,接收操作則是從隊列的頭部刪除元素。如果內部緩存隊列是滿的,那么發(fā)送操作將阻塞直到因另一個goroutine執(zhí)行接收操作而釋放了新的隊列空間。相反,如果channel是空的,接收操作將阻塞直到有另一個goroutine執(zhí)行發(fā)送操作而向隊列插入元素。
- write:緩沖區(qū)被填滿后,寫端才會阻塞。
- read:緩沖區(qū)被讀空,讀端才會阻塞。
可以用內置的cap函數(shù)獲取channel內部緩存的容量
fmt.Println(cap(ch)) // "3"
可以用內置的len函數(shù)獲取channel內部緩存隊列中有效元素的個數(shù)。
fmt.Println(len(ch)) // "2"
到此這篇關于詳解Golang中Channel的用法的文章就介紹到這了,更多相關Golang中Channel用法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- Golang實現(xiàn)Directional Channel(定向通道)
- Golang的select多路復用及channel使用操作
- golang開發(fā)中channel使用
- 基于golang channel實現(xiàn)的輕量級異步任務分發(fā)器示例代碼
- golang中for循環(huán)遍歷channel時需要注意的問題詳解
- golang 函數(shù)返回chan類型的操作