Go学习笔记09-select

什么是select?

select语句用于在多个发送/接收信道操作中进行选择。select语句会一直阻塞,直到发送/接收操作准备就绪。如果有多个信道操作准备完毕,select会随机地选取其中之一执行。该语法与switch类似,不同的是,这里的每个case语句都是信道操作。

select的应用

假设我们有一个关键性应用,需要尽快地把输出返回给用户。这个应用的数据复制并且存储在世界各地的服务器上。假设函数server1server2与这样不同区域的两台服务器进行通信。每台服务器的负载和网络延时决定了它的响应时间。我们向两台服务器发送请求,并使用select语句等待相应的信道发出响应。select会选择首先响应的服务器,而忽略其它的响应。使用这种方法,我们可以向多个服务器发送请求,并给用户返回最快的响应!

默认情况

在没有case准备就绪时,可以执行select语句中的默认情况,这通常用于防止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")
        }
    }
    // output:
    // 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
}

死锁与默认情况

package main

func main() {
    ch := make(chan string)
    select {
    case <-ch: // 由于没有Go协程向该信道写入数据,select语句会一直阻塞,导致死锁
    // 可以在这里添加default,就不会发生死锁
    }
}

随机选取

select中有多个case准备就绪时,将会随机选取其中之一去执行。

空select

package main

func main() {
    select{}
}

我们已经知道,除非有case执行,否则select语句就会一直阻塞着。在上述代码,select语句没有任何case,因此它会一直阻塞,导致死锁。

reference:

https://studygolang.com/articles/12522