概述

select 相似 switch, 蕴含一系列逻辑分支和一个可选的默认分支。每一个分支对应通道上的一次操作 (发送或接管),
能够将 select 了解为专门针对通道操作的 switch 语句

语法规定

select {case v1 := <- ch1:// do something ...  case v2 := <- ch2:// do something ...default:// do something ...}

执行程序

  • 当同时存在多个满足条件的通道时,随机抉择一个执行
  • 如果没有满足条件的通道时,检测是否存在 default 分支

    • 如果存在则执行
    • 否则阻塞期待

通常状况下,把含有 default 分支select 操作称为 无阻塞通道操作

例子

随机执行一个

package mainimport (    "fmt"    "time")func main() {    ch1 := make(chan string)    ch2 := make(chan string)    done := make(chan bool)    go func() {        ch1 <- "hello"    }()    go func() {        ch2 <- "world"    }()    go func() {        done <- true    }()    time.Sleep(time.Second) //  休眠 1 秒    // 此时 3 个通道应该都满足条件,select 会随机抉择一个执行    select {    case msg := <-ch1:        fmt.Printf("ch1 msg = %s\n", msg)    case msg := <-ch2:        fmt.Printf("ch2 msg = %s\n", msg)    case <-done:        fmt.Println("done !")    }    close(ch1)    close(ch2)    close(done)}// $ go run main.go// 输入如下,你的输入可能和这里的不一样, 多运行几次看看成果/**  ch1 msg = hello*/

default (无阻塞通道操作)

package mainimport (    "fmt"    "time")func main() {    ch1 := make(chan string)    ch2 := make(chan string)    done := make(chan bool)    go func() {        time.Sleep(time.Second)        ch1 <- "hello"    }()    go func() {        time.Sleep(time.Second)        ch2 <- "world"    }()    go func() {        time.Sleep(time.Second)        done <- true    }()    // 此时 3 个通道都在休眠中, 不满足条件,select 会执行 default 分支    select {    case msg := <-ch1:        fmt.Printf("ch1 msg = %s\n", msg)    case msg := <-ch2:        fmt.Printf("ch2 msg = %s\n", msg)    case <-done:        fmt.Println("done !")    default:        fmt.Println("default !")    }    close(ch1)    close(ch2)    close(done)}// $ go run main.go// 输入如下/**  default !*/

和 for 搭配应用

通过在 select 外层加一个 for 循环,能够达到 有限轮询 的成果。

package mainimport (    "fmt"    "time")func main() {    ch1 := make(chan string)    ch2 := make(chan string)    done := make(chan bool)    go func() {        // ch1 goroutine 输入 1 次         fmt.Println("[ch1 goroutine]")        time.Sleep(time.Second)        ch1 <- "hello"    }()    go func() {        // ch2 goroutine 输入 2 次        for i := 0; i < 2; i++ {            fmt.Println("[ch2 goroutine]")            time.Sleep(time.Second)        }        ch2 <- "world"    }()    go func() {        // done goroutine 输入 3 次        for i := 0; i < 3; i++ {            fmt.Println("[done goroutine]")            time.Sleep(time.Second)        }        done <- true    }()    for exit := true; exit; {        select {        case msg := <-ch1:            fmt.Printf("ch1 msg = %s\n", msg)        case msg := <-ch2:            fmt.Printf("ch2 msg = %s\n", msg)        case <-done:            fmt.Println("done !")            exit = false // 通过变量管制外层 for 循环退出        }    }    close(ch1)    close(ch2)    close(done)}// $ go run main.go// 输入如下,你的输入程序可能和这里的不一样/**  [done goroutine]  [ch2 goroutine]  [ch1 goroutine]  ch1 msg = hello  [done goroutine]  [ch2 goroutine]  ch2 msg = world  [done goroutine]  done !*/

从输入后果看,[ch1 goroutine] 输入了 1 次,[ch2 goroutine] 输入了 2 次,[done goroutine] 输入了 3 次。

分割我