先來(lái)看看基本的定義:
channel是Go語(yǔ)言中的一個(gè)核心類(lèi)型,可以把它看成管道。并發(fā)核心單元通過(guò)它就可以發(fā)送或者接收數(shù)據(jù)進(jìn)行通訊,這在一定程度上又進(jìn)一步降低了編程的難度。
channel是一個(gè)數(shù)據(jù)類(lèi)型,主要用來(lái)解決go程的同步問(wèn)題以及協(xié)程之間數(shù)據(jù)共享(數(shù)據(jù)傳遞)的問(wèn)題。
(1)channle 本質(zhì)上是一個(gè)數(shù)據(jù)結(jié)構(gòu)——(隊(duì)列),數(shù)據(jù)是先進(jìn)先出。
(2)具有線(xiàn)程安全機(jī)制,多個(gè)go程訪(fǎng)問(wèn)時(shí),不需要枷鎖,也就是說(shuō)channel本身是線(xiàn)程安全的。
(3)channel是有類(lèi)型的,如一個(gè)string類(lèi)型的channel只能存放string類(lèi)型數(shù)據(jù)。
Channel遍歷主要分為3種:
1)簡(jiǎn)單的讀 data:=-ch (如果讀多次,需要用循環(huán))
var ch8 = make(chan int, 6)
func mm1() {
for i := 0; i 10; i++ {
ch8 - 8 * i
}
}
func main() {
go mm1()
for i:=0;i100;i++{
fmt.Print(-ch8, "\t")
}
}
![](/d/20211017/7b1d0af3626196a3c81f4e30f20776f5.gif)
注:
(1)寫(xiě)入的次數(shù)與讀取的次數(shù)需要一致(本例是10);
(2)如果讀的次數(shù)多于寫(xiě)的次數(shù)會(huì)發(fā)生:fatal error: all goroutines are asleep - deadlock! ,若 在mm1中對(duì)ch8進(jìn)行關(guān)閉(執(zhí)行 close(ch8) ),多于的次數(shù)讀到的數(shù)據(jù)為0(數(shù)據(jù)默認(rèn)值)。
(3)讀的次數(shù)少于寫(xiě)的次數(shù),會(huì)讀取出次數(shù)對(duì)應(yīng)的內(nèi)容,不會(huì)報(bào)錯(cuò)。
2)斷言方式
if value, ok := -ch; ok == true {
1) 如果寫(xiě)端沒(méi)有寫(xiě)數(shù)據(jù),也沒(méi)有關(guān)閉。-ch; 會(huì)阻塞 ---【重點(diǎn)】
2)如果寫(xiě)端寫(xiě)數(shù)據(jù), value 保存 -ch 讀到的數(shù)據(jù)。 ok 被設(shè)置為 true
3)如果寫(xiě)端關(guān)閉。 value 為數(shù)據(jù)類(lèi)型默認(rèn)值。ok 被設(shè)置為 false
var ch8 = make(chan int, 6)
func mm1() {
for i := 0; i 10; i++ {
ch8 - 8 * i
}
close(ch8)
}
func main() {
go mm1()
for {
if data, ok := -ch8; ok {
fmt.Print(data,"\t")
} else {
break
}
}
}
![](/d/20211017/6cc2d99695aeabfbdc2499cd64b8cf48.gif)
注:寫(xiě)完之后一定要關(guān)閉( 執(zhí)行:close(ch8) ),否則會(huì)出現(xiàn)以下運(yùn)行結(jié)果:
![](/d/20211017/84a750e1cb65be0bfd650bcf79560e12.gif)
3)通過(guò)range方法
var ch8 = make(chan int, 6)
func mm1() {
for i := 0; i 10; i++ {
ch8 - 8 * i
}
close(ch8)
}
func main() {
go mm1()
for {
for data := range ch8 {
fmt.Print(data,"\t")
}
break
}
}
注:寫(xiě)完之后一定要關(guān)閉( 執(zhí)行:close(ch8) ),否則會(huì)出現(xiàn)以下運(yùn)行結(jié)果:
![](/d/20211017/b1c5648ba13896ffc97c55acd7bb670c.gif)
特別說(shuō)明:以上實(shí)例都是子go程寫(xiě),主go程讀。如在子go程中寫(xiě),另一個(gè)子go程中讀,不管哪種方法,都不會(huì)出現(xiàn)以上錯(cuò)誤問(wèn)題。(多次實(shí)例驗(yàn)證)
var ch8 = make(chan int, 6)
func mm1() {
for i := 0; i 10; i++ {
ch8 - 8 * i
}
//close(ch8)
}
func mm2() {
for {
for data:=range ch8{
fmt.Print(data,"\t")
}
}
}
func main() {
go mm1()
go mm2()
for{
runtime.GC()
}
}
![](/d/20211017/50914273b69cb0650d5de719c072a047.gif)
總結(jié):
通過(guò)以上驗(yàn)證,為了保證程序的健壯性,在設(shè)計(jì)程序時(shí),最好將channel的讀、寫(xiě)分別在子go程中進(jìn)行。寫(xiě)完數(shù)據(jù)之后,記得關(guān)閉channel。
補(bǔ)充一點(diǎn):
1、channel不像文件一樣需要經(jīng)常去關(guān)閉,只有當(dāng)你確實(shí)沒(méi)有任何發(fā)送數(shù)據(jù)了,或者你想顯式的結(jié)束range循環(huán)之類(lèi)的,才去關(guān)閉channel;
2、關(guān)閉channel后,無(wú)法向channel 再發(fā)送數(shù)據(jù)(引發(fā) panic 錯(cuò)誤后導(dǎo)致接收立即返回零值);
3、關(guān)閉channel后,可以繼續(xù)從channel接收數(shù)據(jù);
4、對(duì)于nil channel,無(wú)論收發(fā)都會(huì)被阻塞。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
您可能感興趣的文章:- Golang 空map和未初始化map的注意事項(xiàng)說(shuō)明
- Golang 如何判斷數(shù)組某個(gè)元素是否存在 (isset)
- golang 函數(shù)返回chan類(lèi)型的操作
- Golang 拷貝Array或Slice的操作
- 基于Go Int轉(zhuǎn)string幾種方式性能測(cè)試
- Go語(yǔ)言中break label與goto label的區(qū)別
- Go 實(shí)現(xiàn)英尺和米的簡(jiǎn)單單位換算方式