Go 中的 select 语句允许我们在多个通道中执行一个通道。
在学习 select 之前,请确保您理解 Go Channel。
Select 语句的语法
select {
case firstChannel:
case secondChannel:
case thirdChannel:
}
在这里,select 的每个 case 代表一个独立的通道。并且,根据通道操作的可用性,select 语句会执行一个通道。
注意:select case 的语法与 Go 中的 Switch Case 类似。并且,与 switch case 一样,select 只会执行其中一个 case。
示例:Golang select 语句
package main
import "fmt"
func main() {
// create two channels
number := make(chan int)
message := make(chan string)
// function call with goroutine
go channelNumber(number)
go channelMessage(message)
// selects and executes a channel
select {
case firstChannel := <- number:
fmt.Println("Channel Data:", firstChannel)
case secondChannel := <- message:
fmt.Println("Channel Data:", secondChannel)
}
}
// goroutine to send integer data to channel
func channelNumber(number chan int) {
number <- 15
}
// goroutine to send string data to channel
func channelMessage(message chan string) {
message <- "Learning Go select"
}
输出
Channel Data: Learning Go select
在上面的示例中,我们创建了两个通道 number
和 message。在这里,我们使用了 goroutines
channelNumber()
向 number 通道发送数据channelMessage()
向 message 通道发送数据
该程序包含两个不同的通道,因此我们使用了 select 语句在两个通道中执行其中一个。
select {
case firstChannel := <- number:
fmt.Println("Channel Data:", firstChannel)
case secondChannel := <- message:
fmt.Println("Channel Data:", secondChannel)
}
这里,case firstChannel
从 number 通道接收值并打印它。类似地,case secondChannel
从 message 通道接收值并打印它。
运行此程序时,您可能会得到不同的输出。在我们的示例中,两个通道都已准备好执行,因此 select 语句会随机执行其中一个通道。
Go select 语句,其中一个通道已准备就绪
我们知道,当多个通道都已准备就绪时,select 语句会随机执行其中一个通道。
但是,如果只有一个通道已准备就绪,它将执行该通道。例如,
package main
import (
"fmt"
"time"
)
func main() {
// create channels
number := make(chan int)
message := make(chan string)
// function call with goroutine
go channelNumber(number)
go channelMessage(message)
// selects and executes a channel
select {
case firstChannel := <-number:
fmt.Println("Channel Data:", firstChannel)
case secondChannel := <-message:
fmt.Println("Channel Data:", secondChannel)
}
}
// goroutine to send data to the channel
func channelNumber(number chan int) {
number <- 15
}
// goroutine to send data to the channel
func channelMessage(message chan string) {
// sleeps the process by 2 seconds
time.Sleep(2 * time.Second)
message <- "Learning Go Select"
}
输出
Channel Data: 15
在上面的示例中,我们创建了两个 goroutines,
channelNumber()
- 向 number 通道发送数据channelMessage()
- 向 message 通道发送数据
在 channelMessage()
goroutine 中,我们使用了 time.Sleep()
方法使 message 通道无法执行。
现在,在前 **2** 秒内,只有 number 通道已准备好执行。这就是为什么 select 语句执行 case firstChannel
(number 通道)。
Go select 语句阻止通道
如果通道未准备就绪,select 语句将阻止所有通道。假设在我们之前的示例中,如果 number 和 message 通道都未准备就绪,select 将会阻止两个通道一段时间,直到其中一个可用。
让我们看一个例子。
package main
import (
"fmt"
"time"
)
func main() {
// create channels
number := make(chan int)
message := make(chan string)
// function call with goroutine
go channelNumber(number)
go channelMessage(message)
// selects and executes a channel
select {
case firstChannel := <-number:
fmt.Println("Channel Data:", firstChannel)
case secondChannel := <-message:
fmt.Println("Channel Data:", secondChannel)
}
}
// goroutine to send data to the channel
func channelNumber(number chan int) {
// sleeps the process for 2 seconds
time.Sleep(2 * time.Second)
number <- 15
}
// goroutine to send data to the channel
func channelMessage(message chan string) {
// sleeps the process by 2 seconds
time.Sleep(2 * time.Second)
message <- "Learning Go Select"
}
输出
Channel Data: Learning Go Select
在上面的示例中,我们使用了 time.Sleep()
方法使两个通道在 **2** 秒内都无法执行。
现在,select 语句将在前 **2** 秒内阻止两个通道。这就是为什么在 **2** 秒内我们不会收到任何输出。
然后,它会随机执行其中一个通道,因为 **2** 秒后两个通道都将可用。
Golang select 语句与 default case
当没有通道准备就绪时,select 会阻塞程序。但是,最好显示一些消息,而不是一直阻塞直到通道准备就绪。
为此,我们使用 default
case,如果没有任何通道准备就绪,它将被执行。例如,
package main
import (
"fmt"
"time"
)
func main() {
// create channels
number := make(chan int)
message := make(chan string)
// function call with goroutine
go channelNumber(number)
go channelMessage(message)
// selects and executes a channel
select {
case firstChannel := <-number:
fmt.Println("Channel Data:", firstChannel)
case secondChannel := <-message:
fmt.Println("Channel Data:", secondChannel)
// default case
default:
fmt.Println("Wait!! Channels are not ready for execution")
}
}
// goroutine to send data to the channel
func channelNumber(number chan int) {
// sleeps the process for 2 seconds
time.Sleep(2 * time.Second)
number <- 15
}
// goroutine to send data to the channel
func channelMessage(message chan string) {
// sleeps the process by 2 seconds
time.Sleep(2 * time.Second)
message <- "Learning Go Select"
}
输出
Wait!! Channels are not ready for execution
在上面的示例中,我们为 select 使用了 default
case,如果两个通道都未准备就绪,它将打印 "Wait!! Channels are not ready for execution"
。
由于两个通道都睡眠 **2** 秒,因此它们在最初的 **2** 秒内都不可用。这就是为什么会执行 default
case 的语句。
**2** 秒后,两个通道都将准备就绪,其中一个将由 select 执行。