Go 通道
- 通道作为通信媒介: 在Go中,通道允许goroutines之间进行通信,用于处理并发程序中的资源共享和通信。
- 创建和操作通道: 使用
make()
函数创建通道,并通过<-
运算符向通道发送数据或从通道接收数据。 - 通道的阻塞特性: Go中的通道具有阻塞特性,发送操作会阻塞直到另一个goroutine接收数据,反之亦然。
Go 中的通道作为协程之间进行通信的媒介。
我们知道协程用于创建并发程序。并发程序可以同时运行多个进程。
然而,有时可能会出现两个或更多协程需要相互通信的情况。在这种情况下,我们使用通道,允许协程之间通信和共享资源。
在学习通道之前,请确保了解 Go 中的协程是如何工作的。
在 Go 中创建通道
在 Go 中,我们使用 make()
函数来创建通道。例如,
channelName := make(chan int)
这里,
channelName
- 通道的名称(chan int)
- 表示通道是整数类型的
示例:Go 通道
package main
import "fmt"
func main() {
// 创建整数类型的通道
number := make(chan int)
// 访问通道的类型和值
fmt.Printf("通道类型: %T\n", number)
fmt.Printf("通道值: %v", number)
}
输出
通道类型: chan int
通道值: 0xc00007a060
在上面的例子中,我们使用了 make()
函数创建了名为 number 的通道。这里,我们使用了格式说明符:
%T
- 打印通道的类型%v
- 打印通道的值
由于通道是整数类型的(由 chan int
指定),我们得到了相同的输出。
另外,通道的值是一个内存地址,作为协程发送和接收数据以进行通信的媒介。
Golang 通道操作
创建通道后,我们可以通过通道在不同协程之间发送和接收数据。
1. 向通道发送数据
发送数据到通道的语法是
channelName <- data
这里 <-
运算符后的数据被发送到 channelName。
让我们看一些例子,
// 向通道发送整数数据
number <- 15
// 发送字符串数据
message <- "学习 Go 通道"
2. 从通道接收数据
从通道接收数据的语法是:
<- channelName
这访问了 channelName 的数据。
让我们看一些例子,
// 接收数据 15
<- number
// 接收数据 "学习 Go 通道"
<- message
示例:Go 通道操作
package main
import "fmt"
func main() {
// 创建通道
number := make(chan int)
message := make(chan string)
// 通过协程调用函数
go channelData(number, message)
// 检索通道数据
fmt.Println("通道数据:", <-number)
fmt.Println("通道数据:", <-message)
}
func channelData(number chan int, message chan string) {
// 向通道发送数据
number <- 15
message <- "学习 Go 通道"
}
输出
通道数据: 15
通道数据: 学习 Go 通道
在上面的例子中,我们创建了名为 number 和 message 的两个通道。
这里,我们使用了 <-
运算符来执行从通道发送和接收数据的操作。
通道的阻塞特性
在 Go 中,根据协程的状态,通道自动阻塞发送和接收操作。
1. 当协程向通道发送数据时,操作会被阻塞,直到另一个协程接收到数据。例如,
package main
import "fmt"
func main() {
// 创建通道
ch := make(chan string)
// 通过协程调用函数
go sendData(ch)
// 接收通道数据
fmt.Println(<-ch)
}
func sendData(ch chan string) {
// 数据发送到通道
ch <- "接收成功。发送操作成功"
fmt.Println("无接收者!
发送操作阻塞")
}
输出
无接收者!发送操作阻塞
接收成功。发送操作成功
在上面的例子中,我们创建了 sendData()
协程来向通道发送数据。协程向通道发送字符串数据。
如果通道还没有准备好接收消息,它会打印 "无接收者!发送操作阻塞"
。
在 main()
函数内,我们在接收通道数据之前调用了 sendData()
。这就是为什么首先打印了 "无接收者..."
。
当通道准备好接收数据时,协程发送的数据就会被打印。
2. 当协程从通道接收数据时,如果另一个协程还未向通道发送数据,操作会被阻塞。例如,
package main
import "fmt"
func main() {
// 创建通道
ch := make(chan string)
// 通过协程调用函数
go receiveData(ch)
fmt.Println("无数据。接收操作阻塞")
// 向通道发送数据
ch <- "数据接收。接收操作成功"
}
func receiveData(ch chan string) {
// 从通道接收数据
fmt.Println(<-ch)
}