Go开发Channel彻底研究之Select选择规则

从左往右,从上往下

对于select的求值,一条case中,从左往右求值;多条case,从上往下,下面举几个例子说明:

var ch2 chan int
var ch4 chan int
var chs = []chan int{ch2, ch4}
var numbers = []int{1, 2, 3, 4, 5}
func main() {

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!")
}
}
func getChan(i int) chan int {
fmt.Printf("chs[%d]\n",i);
return chs[i]
}
func getNumber(i int) int {
fmt.Printf("numbers[%d]\n",i)
return numbers[i]
}

代码分析

这段代码设计的也比较巧妙,调试看出getChan先于getNumber执行,说明一条case中是从左往右求值的;同理,多条case是从上往下执行。

但是有一个问题,我们发现ch2和ch4都是nil,简化形式如下:

//ch == nil
var ch chan int

select {
case ch <- 0:
default:
fmt.Println("默认执行...")
}

select的case中允许这样写,但相当于没有写,永远不会执行。除此外,select中还有很多奇怪的使用方式,再比如:

//无缓冲通道
ch := make(chan int)

select {
case ch <- 0:
default:
fmt.Println("默认执行...")
}

没有接收方代码,但是依然也不会错。

具体运行规则

一、在执行select语句时,运行时系统会自上而下判断每个case中的发送或接收操作是否可以被立即执行,这里的立即执行的意思是当前goroutine不会因此操作而阻塞。

要点:case中的语句要能立即执行

二、当发现第一个满足条件的case时,运行时系统就会执行该case所包含的语句,同时,其它case也会被忽略。

要点:只执行一个case

三、如果同时有多个case满足条件,那么运行时会通过一个伪随机的算法决定哪一个case将会执行。

要点:多个case同时满足,使用算法选择一个

chanCap := 5
ch := make(chan int, chanCap)

for i := 0; i < chanCap; i++ {
select {
case ch <- 1:
case ch <- 2:
case ch <- 3:
}
}

for i := 0; i < chanCap; i++ {
fmt.Printf("%v ", <-ch)
}

代码分析

这段代码也很巧妙,验证了多个case同时满足条件时,如何进行随机选择。

输出:

3 2 2 2 3
2 1 1 1 2
1 1 3 2 1

可以看出,作者电脑上每次显示的都是一些随机选择。

四、如果所有的case都不能立即执行,且没有default,那么select会阻塞,直到某个接收或发送的case操作能立即执行。

ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(1 * time.Second)
ch1 <- 10
}()
go func() {
time.Sleep(1 * time.Second)
ch1 <- 20
}()
select {
case d := <-ch1:
fmt.Println(d)
case d := <-ch2:
fmt.Println(d)
}

代码分析

select等待两个channel,由于都延时且没有default,所以select阻塞等待。1s后ch1可以立即执行,因此打印10,select也退出选择。

五、如果所有通道都是nil且没有default,且会发生死锁

// ch1 == nil
var ch1 chan int
select {
case <-ch1:
fmt.Println("hello")
// 没有default
}

select和for的配合

select和for的搭配有很多问题,本篇只说明一个问题:

select的case中可以使用break,但是只跳出select(区域1),如果想跳出for循环(区域2),需要一些辅助技巧。

总结

介绍了select的一些基本选择规则,也是需要背诵的知识点。

网页题目:Go开发Channel彻底研究之Select选择规则
文章网址:http://www.hantingmc.com/qtweb/news44/379444.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联