Channel在Go中充当goroutine之间通信的媒介。
我们知道goroutine用于创建并发程序。并发程序可以同时运行多个进程。
然而,有时可能会出现两个或多个goroutine需要相互通信的情况。在这种情况下,我们使用通道,它允许goroutine相互通信和共享资源。
在学习通道之前,请确保您已了解Go中的Goroutine如何工作。
在Go中创建Channel
在Go中,我们使用make()
函数来创建通道。例如,
channelName := make(chan int)
这里,
channelName
- 通道的名称(chan int)
- 表示通道是整数类型
示例:Go Channel
package main
import "fmt"
func main() {
// create channel of integer type
number := make(chan int)
// access type and value of channel
fmt.Printf("Channel Type: %T\n", number)
fmt.Printf("Channel Value: %v", number)
}
输出
Channel Type: chan int Channel Value: 0xc00007a060
在上面的示例中,我们使用make()
函数创建了一个名为number的通道。这里,我们使用了格式说明符
%T
- 打印通道的类型%v
- 打印通道的值
由于通道是整数类型(由chan int
指定),我们得到相同的输出。
此外,通道的值是内存地址,它充当goroutine发送和接收数据以进行通信的媒介。
Golang Channel 操作
创建通道后,我们可以通过通道在不同的goroutine之间发送和接收数据。
1. 将数据发送到通道
将数据发送到通道的语法是
channelName <- data
这里<-
运算符后的数据被发送到channelName。
让我们看一些例子,
// send integer data to channel
number <- 15
// send string data
message <- "Learning Go Channel"
2. 从通道接收数据
从通道接收数据的语法是
<- channelName
这会访问channelName中的数据。
让我们看一些例子,
// receive data 15
<- number
// receive data "Learning Go Channel"
<- message
示例:Go Channel 操作
package main
import "fmt"
func main() {
// create channel
number := make(chan int)
message := make(chan string)
// function call with goroutine
go channelData(number, message)
// retrieve channel data
fmt.Println("Channel Data:", <-number)
fmt.Println("Channel Data:", <-message)
}
func channelData(number chan int, message chan string) {
// send data into channel
number <- 15
message <- "Learning Go channel"
}
输出
Channel Data: 15 Channel Data: Learning Go Channel
在上面的示例中,我们创建了两个名为number和message的通道。
这里,我们使用了<-
运算符来执行发送和接收通道数据的操作。
通道的阻塞性
在Go中,通道会根据goroutine的状态自动阻塞发送和接收操作。
1. 当goroutine将数据发送到通道时,该操作将被阻塞,直到数据被另一个goroutine接收。例如,
package main
import "fmt"
func main() {
// create channel
ch := make(chan string)
// function call with goroutine
go sendData(ch)
// receive channel data
fmt.Println(<-ch)
}
func sendData(ch chan string) {
// data sent to the channel
ch <- "Received. Send Operation Successful"
fmt.Println("Message sent! Send Operation Complete")
}
输出
Message sent! Send Operation Complete Received. Send Operation Successful
在上面的示例中,我们创建了sendData()
goroutine来向通道发送数据。该goroutine将字符串数据发送到通道。
当sendData()
goroutine将数据发送到通道时,该操作将被阻塞,直到另一个goroutine准备好接收数据。
在main()
函数内部,我们在从通道接收数据之前调用了sendData()
。
但是,sendData()
函数的打印语句只有在数据成功发送并被主goroutine接收后才会执行。
并且,当通道准备好接收数据时,会打印goroutine发送的数据。
2. 当goroutine从通道接收数据时,该操作将被阻塞,直到另一个goroutine将数据发送到通道。例如,
package main
import "fmt"
func main() {
// create channel
ch := make(chan string)
// function call with goroutine
go receiveData(ch)
fmt.Println("No data. Receive Operation Blocked")
// send data to the channel
ch <- "Data Received. Receive Operation Successful"
}
func receiveData(ch chan string) {
// receive data from the channel
fmt.Println(<-ch)
}
输出
No data. Receive Operation Blocked Data Received. Receive Operation Successful
在上面的示例中,我们创建了receiveData()
goroutine来从通道接收数据。该goroutine从通道接收字符串数据。
如果通道尚未发送数据,它将打印“No data. Receive Operation Blocked”
。
在main()
函数内部,我们在将数据发送到通道之前调用了receiveData()
。这就是为什么会打印第一个“No data...”
。
并且,当通道发送数据时,会打印goroutine接收到的数据。