在Go语言中,通道是goroutine与另一个goroutine通信的媒介,并且这种通信是无锁的。换句话说,通道是一种技术,它允许一个goroutine将数据发送到另一个goroutine。默认情况下,通道是双向的,这意味着goroutine可以通过同一通道发送或接收数据,如下图所示:
在Go语言中,使用chan关键字创建通道,并且该通道只能传输相同类型的数据,不允许从同一通道传输不同类型的数据。
语法:
var Channel_name chan Type
您还可以使用简写声明通过make()函数创建通道。
语法:
channel_name:= make(chan Type)
package main import "fmt" func main() { //使用var关键字创建通道 var mychannel chan int fmt.Println("channel的值: ", mychannel) fmt.Printf("channel的类型: %T ", mychannel) // 使用 make() 函数创建通道 mychannel1 := make(chan int) fmt.Println("\nchannel1的值:", mychannel1) fmt.Printf("channel1的类型: %T ", mychannel1) }
输出:
channel的值: <nil> channel的类型: chan int channel1的值: 0xc0000160c0 channel1的类型: chan int
在Go语言中,通道工作有两个主要的操作,一个是发送,另一个是接收,这两个操作统称为通信。<-运算符的方向表示是接收数据还是发送数据。在通道中,默认情况下,发送和接收操作块直到另一端没有数据为止。它允许goroutine在没有显式锁或条件变量的情况下彼此同步。
发送操作:发送操作用于在通道的帮助下将数据从一个goroutine发送到另一个goroutine。像int,float64和bool之类的值可以安全且容易地通过通道发送,因为它们是被复制的,因此不存在意外并发访问相同值的风险。同样,字符串也是安全的,因为它们是不可变的。但是,通过通道发送指针或引用(例如切片,map集合等)并不安全,因为指针或引用的值可能会通过同时发送goroutine或接收goroutine更改,并且结果无法预测。因此,在通道中使用指针或引用时,必须确保它们一次只能由一个goroutine访问。
Mychannel <- element
上面的语句表明数据(element)在<-运算符的帮助下发送到通道(Mychannel)。
接收操作:接收操作用于接收发送操作方发送的数据。
element := <-Mychannel
上面的语句表明该元素从channel(Mychannel)接收数据。如果接收到的语句的结果不可用(不需要使用),则也是有效的语句。您还可以编写如下的receive语句:
<-Mychannel
package main import "fmt" func myfunc(ch chan int) { fmt.Println(234 + <-ch) } func main() { fmt.Println("主方法开始") //创建通道l ch := make(chan int) go myfunc(ch) ch <- 23 fmt.Println("主方法结束") }
输出:
主方法开始 257 主方法结束
您也可以在close()函数的帮助下关闭通道。这是一个内置函数,并设置一个标识,表示不再有任何值将发送到该通道。
语法:
close()
您也可以使用for范围循环关闭通道。在这里,接收器goroutine可以借助给定的语法检查通道是打开还是关闭:
ele, ok:= <- Mychannel
在此,如果ok的值为true,则表示通道已打开,因此可以执行读取操作。并且,如果的值为false,则表示该通道已关闭,因此将不执行读取操作。
//Go程序说明如何 //关闭使用的通道 //range循环和关闭函数 package main import "fmt" func myfun(mychnl chan string) { for v := 0; v < 4; v++ { mychnl <- "cainiaojc" } close(mychnl) } func main() { //创建通道 c := make(chan string) // 使用 Goroutine go myfun(c) //当ok的值为为true时,表示通道已打开,可以发送或接收数据 //当ok的值设置为false时,表示通道已关闭 for { res, ok := <-c if ok == false { fmt.Println("通道关闭 ", ok) break } fmt.Println("通道打开 ", res, ok) } }
输出:
通道打开 cainiaojc true 通道打开 cainiaojc true 通道打开 cainiaojc true 通道打开 cainiaojc true 通道关闭 false
阻止发送和接收:在通道中,当数据发送到通道时,控制在发送语句中被阻塞,直到其他goroutine从该通道读取数据。类似地,当通道从goroutine接收数据时,read语句块直到另一条goroutine语句。
零值通道:通道的零值为nil。
通道中的For循环: for循环可以遍历通道上发送的顺序值,直到关闭为止。
语法:
for item := range Chnl { // 语句.. }
package main import "fmt" func main() { // 使用 make() 函数创建通道 mychnl := make(chan string) // 匿名 goroutine go func() { mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "cainiaojc" close(mychnl) }() //使用for循环 for res := range mychnl { fmt.Println(res) } }
输出:
GFG gfg Geeks cainiaojc$1/pre>
通道的长度:在通道中,您可以使用len()函数找到通道的长度。在此,长度表示在通道缓冲区中排队的值的数量。
package main import "fmt" func main() { // 使用 make() 函数创建通道 mychnl := make(chan string, 4) mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "cainiaojc" // 使用 len() 函数查找通道的长度 fmt.Println("channel长度为: ", len(mychnl)) }
输出:
channel长度为: 4
通道的容量:在通道中,您可以使用cap()函数找到通道的容量。在此,容量表示缓冲区的大小。
package main import "fmt" func main() { // 使用 make() 函数创建通道 mychnl := make(chan string, 4) mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "cainiaojc" // 使用 cap() 函数查找通道的容量 fmt.Println("channel容量为: ", cap(mychnl)) }
输出:
channel容量为: 5
Channel中的Select和case语句:在go语言中,select语句就像没有任何输入参数的switch语句。在通道中使用select语句从case块提供的多个操作中执行单个操作。