Go语言入门—16Select

144 阅读3分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战」。

select

select 是 go 语言中的一种条件控制语句,类似于之前学习的 switch 条件控制语句,不同的是 select 只能用于通道的控制,在 select 中同样可以有多个 case 分支和一个 default 分支,但是每一个 case 必须都是 channel 的操作,可以是发送也可以是接收,select 会一直等待,直到某一个 case 分支的 channel 操作完成之后就执行对应的代码语句。

基本语法:

select {
    case channel 语句 1 :
       // 匹配到 channel 语句 1 则执行该内容
    case channel 语句 2 :
       // 匹配到 channel 语句 1 则执行该内容
    default :	// 默认执行
       // default 内容
}

select 同时监听多个分支,一直堵塞直到其中一个分支完成 channel

代码示例:

package main

import (
	"fmt"
)

func main() {
	intChan := make(chan int)
	stringChan := make(chan string)

	go func(ch chan int) {
		time.Sleep(time.Second * 2)
		ch <- 1
	}(intChan)

	go func(ch chan string) {
		time.Sleep(time.Second)
		ch <- "a"
	}(stringChan)

	select {
	case i := <- intChan:		// 监听 intChan 的操作
		fmt.Println(i)
	case s := <- stringChan:	// 监听 stringChan 的操作
		fmt.Println(s)
	}
}

上述代码中的 select 有两个 case 分支,分别监听了 intChan 和 stringChan 两个通道,然后在程序中启动两个 goroutine 分别对这两个通道发送数据,则 select 会一直堵塞,直到其中一个 case 的 channel 接收到数据就执行其对应的输出语句,由于在往 intChan 中发送数据之前有两秒钟的睡眠时间, stringChan 只有一秒钟的睡眠时间,所以当前代码中永远都是 stringChan 先好,最后的结果则是在控制台打印字母 a。

在 select 中增加 default 语句后则不会一直堵塞等待

代码示例:

select {
    case i := <- intChan:
    	fmt.Println(i)
    case s := <-stringChan:
    	fmt.Println(s)
    default:
    	fmt.Println("default操作")
}

在保持上面代码都不变的情况下,仅在 select 语句的最后加入一个 default 分支,这样再次运行代码就会打印输出 default操作,这是因为在 select 语句中加入 default 之后就不会堵塞等待,而且在 intChan 和 stringChan 中分别有一秒和两秒的沉睡,当执行到 select 语句时,两个 channel 都没有准备好,就会直接执行 default 分支的内容。

当多个 channel 同时准备好时,随机执行其中一个

代码示例:

package main

import (
	"fmt"
	"time"
)

func main() {
	intChan := make(chan int)
	stringChan := make(chan string)

	go func(ch chan int) {
		ch <- 1
	}(intChan)

	go func(ch chan string) {
		ch <- "a"
	}(stringChan)

	time.Sleep(time.Second)		// 睡眠一秒钟,确保两个 channel 都准备好

	select {
	case i := <- intChan:
		fmt.Println(i)
	case s := <-stringChan:
		fmt.Println(s)
	}
}

上面的代码中,在 select 语句之前睡眠了一秒钟,用于确保前面两个 goroutine 都执行完毕并把数据发送到 channel 中,然后再执行后面的 select 语句,这时候执行到 select 语句时,intChan 和 stringChan 都是准备就绪状态,则这时候 select 会随机选择一个 case 分支执行,所以在最后的输出结果中会随机在控制台打印数字 1 或者字母 a。

select 总结:

  1. 每一个 case 都必须是一个通道操作。
  2. 没有 default 分支时,select 会堵塞,有 default 分支时直接执行 default 分支内容。
  3. 如果有多个 case 分支同时准备就绪,则随机执行其中一个,其他的则忽略。

关注专栏,持续更新

公众号:CodeJR,关注查看更多文章与干货,回复golang领取golang学习电子书。