在 Go 语言中,通道是一个 goroutine 与另一个 goroutine 通信的媒介,并且这种通信是无锁的。或者换句话说,通道是一种允许让一个 goroutine 向另一个 goroutine 发送数据的技术。默认情况下通道是双向的,这意味着 goroutine 可以通过相同的通道发送或接收数据,如下图所示:
创建频道
在 Go 语言中,通道是使用 chan 关键字创建的,它只能传输相同类型的数据,不允许从同一通道传输不同类型的数据。
句法:
var Channel_name chan Type
您还可以使用 make()函数使用速记声明创建通道。
句法:
channel_name:= make(chan Type)
例子:
// Go program to illustrate
// how to create a channel
package main
import "fmt"
func main() {
// Creating a channel
// Using var keyword
var mychannel chan int
fmt.Println("Value of the channel: ", mychannel)
fmt.Printf("Type of the channel: %T ", mychannel)
// Creating a channel using make() function
mychannel1 := make(chan int)
fmt.Println("\nValue of the channel1: ", mychannel1)
fmt.Printf("Type of the channel1: %T ", mychannel1)
}
输出:
Value of the channel:
Type of the channel: chan int
Value of the channel1: 0x432080
Type of the channel1: chan int
从通道发送和接收数据
在 Go 语言中,通道工作有两个主要操作,一个是发送,另一个是接收,这两个操作统称为通信。而<-运算符的方向表示数据是接收还是发送。在通道中,发送和接收操作会阻塞,直到另一端默认没有准备好。它允许 goroutine 在没有显式锁或条件变量的情况下相互同步。
- 发送操作:发送操作用于在通道的帮助下将数据从一个 goroutine 发送到另一个 goroutine。像 int、float64 和 bool 这样的值可以安全且容易地通过通道发送,因为它们是复制的,因此不存在意外并发访问相同值的风险。同样,字符串也可以安全传输,因为它们是不可变的。但是对于通过通道发送指针或引用(如切片、映射等)是不安全的,因为指针或引用的值可能会通过发送 goroutine 或同时接收 goroutine 而改变,并且结果是不可预测的。因此,当您在通道中使用指针或引用时,您必须确保它们一次只能由一个 goroutine 访问。
Mychannel <- element
上面的语句表明数据(元素)在<-运算符的帮助下发送到通道(Mychannel)。
- 接收操作:接收操作用于接收发送运算符发送的数据。
element := <-Mychannel
上面的语句表示元素从通道(Mychannel)接收数据。如果接收到的结果语句不打算使用也是一个有效的语句。您还可以将接收语句编写为:
<-Mychannel
例子:
// Go program to illustrate send
// and receive operation
package main
import "fmt"
func myfunc(ch chan int) {
fmt.Println(234 + <-ch)
}
func main() {
fmt.Println("start Main method")
// Creating a channel
ch := make(chan int)
go myfunc(ch)
ch <- 23
fmt.Println("End Main method")
}
输出:
start Main method
257
End Main method
关闭频道
您还可以在 close()函数的帮助下关闭通道。这是一个内置函数,并设置一个标志,指示不会再向此通道发送任何值。
句法:
close()
您还可以使用 for range 循环关闭通道。在这里,接收器 goroutine 可以在给定语法的帮助下检查通道是打开还是关闭:
ele, ok:= <- Mychannel
在这里,如果 ok 的值为真,则表示通道已打开,则可以执行读取操作。如果 的值为 false,这意味着通道已关闭,则不会执行读取操作。
例子:
// Go program to illustrate how
// to close a channel using for
// range loop and close function
package main
import "fmt"
// Function
func myfun(mychnl chan string) {
for v := 0; v < 4; v++ {
mychnl <- "GeeksforGeeks"
}
close(mychnl)
}
// Main function
func main() {
// Creating a channel
c := make(chan string)
// calling Goroutine
go myfun(c)
// When the value of ok is
// set to true means the
// channel is open and it
// can send or receive data
// When the value of ok is set to
// false means the channel is closed
for {
res, ok := <-c
if ok == false {
fmt.Println("Channel Close ", ok)
break
}
fmt.Println("Channel Open ", res, ok)
}
}
输出:
Channel Open GeeksforGeeks true
Channel Open GeeksforGeeks true
Channel Open GeeksforGeeks true
Channel Open GeeksforGeeks true
Channel Close false
要点
- 阻塞发送和接收:在通道中,当数据发送到通道时,控制在该发送语句中被阻塞,直到其他 goroutine 从该通道读取。类似地,当一个通道从 goroutine 接收数据时,read 语句会阻塞直到另一个 goroutine 语句。
- 零值通道:通道的零值为零。
- Channel 中的 for 循环: for 循环可以迭代通道上发送的顺序值,直到它关闭。
句法:
for item := range Chnl { // statements.. }
例子:
// Go program to illustrate how to // use for loop in the channel package main import "fmt" // Main function func main() { // Creating a channel // Using make() function mychnl := make(chan string) // Anonymous goroutine go func() { mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "GeeksforGeeks" close(mychnl) }() // Using for loop for res := range mychnl { fmt.Println(res) } }
输出:
GFG gfg Geeks GeeksforGeeks
- 通道长度:在通道中,您可以使用len()函数找到通道的长度。这里,长度表示在通道缓冲区中排队的值的数量。
例子:
// Go program to illustrate how to // find the length of the channel package main import "fmt" a // Main function func main() { // Creating a channel // Using make() function mychnl := make(chan string, 4) mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "GeeksforGeeks" // Finding the length of the channel // Using len() function fmt.Println("Length of the channel is: ", len(mychnl)) }
输出:
Length of the channel is: 4
- 频道容量:在频道中,您可以使用 cap()函数找到频道的容量。这里,容量表示缓冲区的大小。
例子:
// Go program to illustrate how to // find the capacity of the channel package main import "fmt" // Main function func main() { // Creating a channel // Using make() function mychnl := make(chan string, 5) mychnl <- "GFG" mychnl <- "gfg" mychnl <- "Geeks" mychnl <- "GeeksforGeeks" // Finding the capacity of the channel // Using cap() function fmt.Println("Capacity of the channel is: ", cap(mychnl)) }
输出:
Capacity of the channel is: 5
- Channel中的select和case语句:在go语言中,select语句就像一个没有任何输入参数的switch语句。此 select 语句用于在通道中执行 case 块提供的多个操作中的单个操作。