Go select

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

在上面的示例中,我们创建了两个通道 numbermessage。在这里,我们使用了 goroutines

  • channelNumber()number 通道发送数据
  • channelMessage()message 通道发送数据

该程序包含两个不同的通道,因此我们使用了 select 语句在两个通道中执行其中一个。

select {

  case firstChannel := <- number:
    fmt.Println("Channel Data:", firstChannel)

  case secondChannel := <- message:
    fmt.Println("Channel Data:", secondChannel)
}

这里,case firstChannelnumber 通道接收值并打印它。类似地,case secondChannelmessage 通道接收值并打印它。

运行此程序时,您可能会得到不同的输出。在我们的示例中,两个通道都已准备好执行,因此 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 firstChannelnumber 通道)。


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 执行。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战