golang 非缓冲channel select阻塞进入default

1.说明

首先说明一下非缓冲channel和缓冲channel
golang中用make创建channel时,可以传入一个数值,用于指定channel的容量,这样的channel就是一个缓冲channel

// 非缓冲channel
var channel1 = make(chan int)
// 缓冲channel(容量为1)
var channel2 = make(chan int ,1)

2.案例分析

创建一个demo2.go文件

package main

import "fmt"

var channel1 chan int

var channel2 = make(chan int)

var channel3 chan int

func main() {

	select {
	case channel1 <- 1:
		fmt.Println("channel1放入了一个值")
	case channel2 <- 2:
		fmt.Println("channel2放入了一个值")
	case channel3 <- 3:
		fmt.Println("channel3放入了一个值")
	default:
		fmt.Println("没有进入任何case")
	}

}

go run demo2.go输出结果如下

laptop@localhost go_study % go run demo2.go 
没有进入任何case

将channel2的申明方式改为

var channel2 = make(chan int ,1)

go run demo2.go输出结果如下

laptop@localhost go_study % go run demo2.go
channel2放入了一个值 

可以看到非缓冲channel的select总是进入default(即没有case符合条件),缓存channel顺利的进入了case

3.问题解析

select执行有如下规则:

  • select中所有的case如果存在运算符,则会按照case的顺序从上到下依次计算求得结果,然后根据是否符合条件,进入符合条件的case,如果存在多个符合条件的case,select会采用伪随机算法,选择一个case进入
  • 针对非缓冲channel或者channel为nil的,case会一直阻塞。select在所有的case都阻塞或者不满足条件的情况下,会进入default

由此我们可以看出,非缓冲channel的select总是进入default是因为case被阻塞了,第一个和第三个case是因为channel为nil导致的,第二个case阻塞是因为:非缓冲channel的收发必须在收发双方都就绪的情况下,一收一发才不会阻塞,这里的case只是一个单纯的发送操作,会阻塞。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×