Go教程-初识Select|Go主题月

229 阅读3分钟

本文为翻译文章

原文地址:golangbot.com/select/

什么是 select?

select 语句用于从多个发送/接收通道操作中进行选择。select 语句将阻塞,直到发送/接收操作之一准备就绪为止。如果准备好多个操作,则随机选择其中之一。语法与 switch 相似,不同之处在于每个 case 语句将是一个通道操作。让我们深入研究一些代码以更好地理解。

例子

package main

import (  
    "fmt"
    "time"
)

func server1(ch chan string) {  
    time.Sleep(6 * time.Second)
    ch <- "from server1"
}
func server2(ch chan string) {  
    time.Sleep(3 * time.Second)
    ch <- "from server2"

}
func main() {  
    output1 := make(chan string)
    output2 := make(chan string)
    go server1(output1)
    go server2(output2)
    select {
    case s1 := <-output1:
        fmt.Println(s1)
    case s2 := <-output2:
        fmt.Println(s2)
    }
}

在上面代码中,server1 函数睡眠了 6 秒后,然后将字符串 from server1 写入了 ch 通道。server2 函数里睡眠了 3 秒后将 from server2 字符串写入了 ch 通道。

主函数中开启了两个Goroutine server1和 server2。

当执行到 select 语句后,select 语句将阻塞,直到其中一种情况准备就绪为止。在上面的程序中,server1 Goroutine 在 6 秒后写入 output1 通道,而 server2 在 3 秒后写入 output2 通道。因此,select 语句将阻塞 3 秒钟,并等待 server2 Goroutine 写入 output2 通道。 3 秒钟后,程序将打印:

from server2

然后将终止。

实际使用 select

将上面程序中的功能命名为 server1 和 server2 的原因是为了说明 select 的实际用法。

假设我们有一个关键任务应用程序,我们需要尽快将输出返回给用户。此应用程序的数据库已复制并存储在世界各地的不同服务器中。假定功能server1server2实际上与 2 台这样的服务器进行通信。每个服务器的响应时间取决于每个服务器的负载和网络延迟。我们将请求发送到两个服务器,然后使用该select语句在相应的通道上等待响应。由选择选择首先响应的服务器,而忽略其他响应。这样,我们可以将相同的请求发送到多台服务器,并将最快的响应返回给用户:)。

Default 关键字

当其他情况都不准备就绪时,将执行 select 语句中的 Default。通常用于防止 select 语句被阻塞。

package main

import (  
    "fmt"
    "time"
)

func process(ch chan string) {  
    time.Sleep(10500 * time.Millisecond)
    ch <- "process successful"
}

func main() {  
    ch := make(chan string)
    go process(ch)
    for {
        time.Sleep(1000 * time.Millisecond)
        select {
        case v := <-ch:
            fmt.Println("received value: ", v)
            return
        default:
            fmt.Println("no value received")
        }
    }

}

在上面的程序中,process 函数 睡眠10500毫秒(10.5秒),然后将 process successful 写入 ch 通道。主 Goroutine 创建了一个 process Goroutine。

同时调用 process Goroutine 后,主 Goroutine 中将启动一个无限 for 循环。无限循环在每次迭代开始时睡眠 1000 毫秒(1秒),然后执行选择操作。在最初的 10500 毫秒内,select 语句的第一种情况即case v := <-ch:未准备就绪,因为 process Goroutine 里的 ch 通道仅在 10500 毫秒后才写入数据。因此,该 default 将在这段时间内执行,程序将打印 no value received 10 次。

10.5 秒后,process Goroutine 写入process successfulch 通道。现在,将执行 select 语句的第一种情况,程序将打印 received value: process successful,然后终止。该程序将输出:

no value received  
no value received  
no value received  
no value received  
no value received  
no value received  
no value received  
no value received  
no value received  
no value received  
received value:  process successful