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