在Go語(yǔ)言中,通道是goroutine與另一個(gè)goroutine通信的媒介,并且這種通信是無(wú)鎖的。換句話說(shuō),通道是一種技術(shù),它允許一個(gè)goroutine將數(shù)據(jù)發(fā)送到另一個(gè)goroutine。默認(rèn)情況下,通道是雙向的,這意味著goroutine可以通過(guò)同一通道發(fā)送或接收數(shù)據(jù),如下圖所示:
在Go語(yǔ)言中,使用chan關(guān)鍵字創(chuàng)建通道,并且該通道只能傳輸相同類型的數(shù)據(jù),不允許從同一通道傳輸不同類型的數(shù)據(jù)。
語(yǔ)法:
var Channel_name chan Type
您還可以使用簡(jiǎn)寫(xiě)聲明通過(guò)make()函數(shù)創(chuàng)建通道。
語(yǔ)法:
channel_name:= make(chan Type)
package main import "fmt" func main() { //使用var關(guān)鍵字創(chuàng)建通道 var mychannel chan int fmt.Println("channel的值: ", mychannel) fmt.Printf("channel的類型: %T ", mychannel) // 使用 make() 函數(shù)創(chuàng)建通道 mychannel1 := make(chan int) fmt.Println("\nchannel1的值:", mychannel1) fmt.Printf("channel1的類型: %T ", mychannel1) }
輸出:
channel的值: <nil> channel的類型: chan int channel1的值: 0xc0000160c0 channel1的類型: chan int
在Go語(yǔ)言中,通道工作有兩個(gè)主要的操作,一個(gè)是發(fā)送,另一個(gè)是接收,這兩個(gè)操作統(tǒng)稱為通信。<-運(yùn)算符的方向表示是接收數(shù)據(jù)還是發(fā)送數(shù)據(jù)。在通道中,默認(rèn)情況下,發(fā)送和接收操作塊直到另一端沒(méi)有數(shù)據(jù)為止。它允許goroutine在沒(méi)有顯式鎖或條件變量的情況下彼此同步。
發(fā)送操作:發(fā)送操作用于在通道的幫助下將數(shù)據(jù)從一個(gè)goroutine發(fā)送到另一個(gè)goroutine。像int,float64和bool之類的值可以安全且容易地通過(guò)通道發(fā)送,因?yàn)樗鼈兪潜粡?fù)制的,因此不存在意外并發(fā)訪問(wèn)相同值的風(fēng)險(xiǎn)。同樣,字符串也是安全的,因?yàn)樗鼈兪遣豢勺兊?。但是,通過(guò)通道發(fā)送指針或引用(例如切片,map集合等)并不安全,因?yàn)橹羔樆蛞玫闹悼赡軙?huì)通過(guò)同時(shí)發(fā)送goroutine或接收goroutine更改,并且結(jié)果無(wú)法預(yù)測(cè)。因此,在通道中使用指針或引用時(shí),必須確保它們一次只能由一個(gè)goroutine訪問(wèn)。
Mychannel <- element
上面的語(yǔ)句表明數(shù)據(jù)(element)在<-運(yùn)算符的幫助下發(fā)送到通道(Mychannel)。
接收操作:接收操作用于接收發(fā)送操作方發(fā)送的數(shù)據(jù)。
element := <-Mychannel
上面的語(yǔ)句表明該元素從channel(Mychannel)接收數(shù)據(jù)。如果接收到的語(yǔ)句的結(jié)果不可用(不需要使用),則也是有效的語(yǔ)句。您還可以編寫(xiě)如下的receive語(yǔ)句:
<-Mychannel
package main import "fmt" func myfunc(ch chan int) { fmt.Println(234 + <-ch) } func main() { fmt.Println("主方法開(kāi)始") //創(chuàng)建通道l ch := make(chan int) go myfunc(ch) ch <- 23 fmt.Println("主方法結(jié)束") }
輸出:
主方法開(kāi)始 257 主方法結(jié)束
您也可以在close()函數(shù)的幫助下關(guān)閉通道。這是一個(gè)內(nèi)置函數(shù),并設(shè)置一個(gè)標(biāo)識(shí),表示不再有任何值將發(fā)送到該通道。
語(yǔ)法:
close()
您也可以使用for范圍循環(huán)關(guān)閉通道。在這里,接收器goroutine可以借助給定的語(yǔ)法檢查通道是打開(kāi)還是關(guān)閉:
ele, ok:= <- Mychannel
在此,如果ok的值為true,則表示通道已打開(kāi),因此可以執(zhí)行讀取操作。并且,如果的值為false,則表示該通道已關(guān)閉,因此將不執(zhí)行讀取操作。
//Go程序說(shuō)明如何 //關(guān)閉使用的通道 //range循環(huán)和關(guān)閉函數(shù) package main import "fmt" func myfun(mychnl chan string) { for v := 0; v < 4; v++ { mychnl <- "nhooo" } close(mychnl) } func main() { //創(chuàng)建通道 c := make(chan string) // 使用 Goroutine go myfun(c) //當(dāng)ok的值為為true時(shí),表示通道已打開(kāi),可以發(fā)送或接收數(shù)據(jù) //當(dāng)ok的值設(shè)置為false時(shí),表示通道已關(guān)閉 for { res, ok := <-c if ok == false { fmt.Println("通道關(guān)閉 ", ok) break } fmt.Println("通道打開(kāi) ", res, ok) } }
輸出:
通道打開(kāi) nhooo true 通道打開(kāi) nhooo true 通道打開(kāi) nhooo true 通道打開(kāi) nhooo true 通道關(guān)閉 false
阻止發(fā)送和接收:在通道中,當(dāng)數(shù)據(jù)發(fā)送到通道時(shí),控制在發(fā)送語(yǔ)句中被阻塞,直到其他goroutine從該通道讀取數(shù)據(jù)。類似地,當(dāng)通道從goroutine接收數(shù)據(jù)時(shí),read語(yǔ)句塊直到另一條goroutine語(yǔ)句。
零值通道:通道的零值為nil。
通道中的For循環(huán): for循環(huán)可以遍歷通道上發(fā)送的順序值,直到關(guān)閉為止。
語(yǔ)法:
for item := range Chnl { // 語(yǔ)句.. }
package main import "fmt" func main() { // 使用 make() 函數(shù)創(chuàng)建通道 mychnl := make(chan string) // 匿名 goroutine go func() { mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "nhooo" close(mychnl) }() //使用for循環(huán) for res := range mychnl { fmt.Println(res) } }
輸出:
GFG gfg Geeks nhooo
通道的長(zhǎng)度:在通道中,您可以使用len()函數(shù)找到通道的長(zhǎng)度。在此,長(zhǎng)度表示在通道緩沖區(qū)中排隊(duì)的值的數(shù)量。
package main import "fmt" func main() { // 使用 make() 函數(shù)創(chuàng)建通道 mychnl := make(chan string, 4) mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "nhooo" // 使用 len() 函數(shù)查找通道的長(zhǎng)度 fmt.Println("channel長(zhǎng)度為: ", len(mychnl)) }
輸出:
channel長(zhǎng)度為: 4
通道的容量:在通道中,您可以使用cap()函數(shù)找到通道的容量。在此,容量表示緩沖區(qū)的大小。
package main import "fmt" func main() { // 使用 make() 函數(shù)創(chuàng)建通道 mychnl := make(chan string, 4) mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "nhooo" // 使用 cap() 函數(shù)查找通道的容量 fmt.Println("channel容量為: ", cap(mychnl)) }
輸出:
channel容量為: 5
Channel中的Select和case語(yǔ)句:在go語(yǔ)言中,select語(yǔ)句就像沒(méi)有任何輸入?yún)?shù)的switch語(yǔ)句。在通道中使用select語(yǔ)句從case塊提供的多個(gè)操作中執(zhí)行單個(gè)操作。