22、go语言select语句块


转载:https://www.jianshu.com/p/2a1146dc42c3

1、基本用法

select是用来监听和channel有关的IO操作,当IO操作发生时,触发对应的动作

select {
case <- chan1:
//如果chan1成功读取到数据,则进行该case处理语句
case chan2 <- 2:
//若成功向chan2写入数据,则进行该case处理语句
default:
//如果上面都没有成功, 则进入default处理语句(default选填)
}

2、简介

所有channel表达式都会被求值、所有被发送的表达式都会被求值。求值顺序:自上而下、从左到右。


结果是选择一个发送或接收的channel,无论选择哪一个case进行操作,表达式都会被执行。


如果有一个或多个IO操作可以完成,则go会随机选择一个执行,否则的话,如果有default分支,则执行default分支,如果连default都没有,则select语句会一直阻塞,直到至少有一个IO操作可以进行

3、example 1

如果有一个或多个IO操作可以完成,则GO运行时系统会随机的选择一个执行,否则,若有default分支,则执行default分支,如果连default分支都没有,则select语句会一直阻塞,直到至少有一个IO操作可以运行

	start := time.Now()
	c := make(chan interface{})
	ch1 := make(chan int)
	ch2 := make(chan int)
	go func() {
		time.Sleep( 4 * time.Second)
		close(c)
	}()
	go func() {
		time.Sleep( 3 * time.Second)
		ch1 <- 3
	}()
	go func() {
		time.Sleep( 3 * time.Second)
		ch2 <- 5
	}()
	fmt.Println("Blocking on read:")
	select {
	case <- c:
		fmt.Printf("Unblocked %v later.\n", time.Since(start))
	case <- ch1:
		fmt.Printf("ch1 case...\n")
	case <- ch2:
		fmt.Printf("ch2 case ...\n")
	default:
		fmt.Printf("default go...")
	}

运行上述代码,由于当前时间未到3s,所以,程序会走default

Blocking on read:
default go...
Process finished with exit code 0

修改代码,将default注释掉:

//default:
		//fmt.Printf("default go...")

这时,select语句会阻塞,直到检测到一个可以执行的IO操作为止,这里先会执行完睡眠3s的gorountine,此时两个channel都满足条件,这时系统会随机选择一个case继续操作

Blocking on read:
ch2 case ...

Process finished with exit code 0

接着,继续修改代码,将ch1和ch2的goroutine休眠时间改为5S:

	go func() {
		time.Sleep( 5 * time.Second)
		ch1 <- 3
	}()
	go func() {
		time.Sleep( 5 * time.Second)
		ch2 <- 5
	}()

此时会先执行到上面的gorountine,select执行的就是c的case

Blocking on read:
Unblocked 4.0008118s later.

Process finished with exit code 0

4、example 4

所有channel表达式都会被求值、所有被发送的表达式都会被求值。求值顺序:自上而下,从左到右:

var ch1 chan int
var ch2 chan int
var chs = []chan int{ch1, ch2}
var numbers = []int{1, 2, 3, 4, 5}

func getNumber(i int) int {
	fmt.Printf("numbers[%d]\n", i)
	return numbers[i]
}
func getChan(i int) chan int {
	fmt.Printf("chs[%d]\n", i)
	return chs[i]
}
func chanOrderDemo()  {
	select {
	case getChan(0) <- getNumber(2):
		fmt.Println("1th case is selected.")
	case getChan(1) <- getNumber(3):
		fmt.Println("2th case is selected.")
	default:
		fmt.Println("default!.")
	}
}

此时,select语句走的是default操作,但是这是每个case表达式都会被执行:以case1为例:

case getChan(0) <- getNumber(2):

系统会从左到右先执行getChan(0)并打印chs[0]执行,然后执行 getNumber(2)函数打印numbers[2]。同样,从上到下分别执行所有case的语句。所以执行结果为:

chs[0]
numbers[2]
chs[1]
numbers[3]
default!.

Process finished with exit code 0

5、example 5

break关键字结束select

func selectUseBreak(){
	ch1 := make(chan int, 1)
	ch2 := make(chan int, 1)

	ch1 <- 3
	ch2 <- 5
	select {
	case <- ch1:
		fmt.Println("ch1 selected")
		break
		fmt.Println("ch1 selected after break")
	case <- ch2:
		fmt.Println("ch2 selected.")
		fmt.Println("ch2 selected without break")
	}
}

很明显,ch1和ch2两个通道都可以读取到值,所以系统会随机选择一个case执行。我们发现选择执行ch1的case时,由于有break关键字,所以只执行了一句:

ch1 selected

Process finished with exit code 0

但是,当系统选择ch2的case时,打印结果为:

ch2 selected.
ch2 selected without break

Process finished with exit code 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值