点击上方蓝色“ Go语言中文网 ”关注, 每天一起学 Go

欢迎来到 Golang 系列教程[1]的第 24 篇。

什么是 select?

selectselectselectswitchcase

示例

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 :=         fmt.Println(s1)
    case s2 :=         fmt.Println(s2)
    }
}

在线运行程序[2]

server1from server1chserver2from server2ch
mainserver1server2
selectselectserver1output1server2output2selectserver2output2
from server2

然后程序终止。

select 的应用

server1server2select
server1server2selectselect

默认情况

selectselect
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 :=             fmt.Println("received value: ", v)
            return
        default:
            fmt.Println("no value received")
        }
    }

}

在线运行程序[3]

processprocess successfulch
processprocesschselectcase v := )并未就绪。所以在这期间,程序会执行默认情况,该程序会打印 10 次 no value received。no value received
processchprocess successfulselectreceived 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

死锁与默认情况

package main

func main() {
    ch := make(chan string)
    select {
    case     }
}

在线运行程序[4]

chselectchselectpanic
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
    /tmp/sandbox416567824/main.go:6 +0x80

如果存在默认情况,就不会发生死锁,因为在没有其他 case 准备就绪时,会执行默认情况。我们用默认情况重写后,程序如下:

package main

import "fmt"

func main() {
    ch := make(chan string)
    select {
    case     default:
        fmt.Println("default case executed")
    }
}

在线运行程序[5]

以上程序会输出:

default case executed
selectnil
package main

import "fmt"

func main() {
    var ch chan string
    select {
    case v :=         fmt.Println("received value", v)
    default:
        fmt.Println("default case executed")

    }
}

在线运行程序[6]

chnilselectchselectselect
default case executed

随机选取

select
package main

import (
    "fmt"
    "time"
)

func server1(ch chan string) {
    ch "from server1"
}
func server2(ch chan string) {
    ch "from server2"

}
func main() {
    output1 := make(chan string)
    output2 := make(chan string)
    go server1(output1)
    go server2(output2)
    time.Sleep(1 * time.Second)
    select {
    case s1 :=         fmt.Println(s1)
    case s2 :=         fmt.Println(s2)
    }
}

在线运行程序[7]

server1server2selectserver1from server1output1server2from server2output2selectfrom server1from server2

请在你的本地系统上运行这个程序,获得程序的随机结果。因为如果你在 playground 上在线运行的话,它的输出总是一样的,这是由于 playground 不具有随机性所造成的。

这下我懂了:空 select

package main

func main() {
    select {}
}

在线运行程序[8]

你认为上面代码会输出什么?

select
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [select (no cases)]:
main.main()
    /tmp/sandbox299546399/main.go:4 +0x20

本教程到此结束。祝你愉快。

上一教程 - 缓冲信道和工作池

下一教程 - Mutex[9]

推荐阅读

  • Go 经典入门系列 23:缓冲信道和工作池

福利 我为大家整理了一份 从入门到进阶的Go学习资料礼包 ,包含学习建议:入门看什么,进阶看什么。 关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。

98f895e01bff3430926e25d462f5ac64.png