golang select是多 channel 并行的利器
不要拿 switch 和 select 比,根本不是一个东西好嘛,差不少,只是名字稍微有点像
前置操作
golang 对 select 做了一些优化
select 结构体为空
当 select 里面为空的时候会直接 panic
只有一个 case
当只有一个 case 时候(包括只有一个 case 时候),会将 select 去掉
select{
case c <- x:
return
}
转变成
c <- x
return
当有单一 case 加 default
当只有一个 case 和一个 default 时候,会转变成非阻塞的 if 操作
select{
case c <- x:
print("ok")
default:
print("default")
}
转变成
if (chansend()/chanrecv()){ // 非阻塞的 chansend 或 chanrecv 操作,有个 block 参数代表阻塞在通道那篇的源码有
print("ok")
}else{
print("default")
}
流程
当有两个以上的 case 时候,也就是普通的时候,会执行下面流程
- 先把所有的 channel 打乱,放入到lockorder中
- 然后把 lockerorder 中的 channel 都加锁
- 然后查看 pollorder 中是否有就绪的 channel,如果有的话就执行 send/recv 操作,将所有的其他channel 解锁
- 如果没有,就把当前协程加入所有对应发送/接受channel 的等待队列,然后将自己挂起(其实这个操作和一个普通goroutine 一样,都是将自己放到 channel 等待队列),然后解锁(源码没看到解锁)
- 等某一个 channel 可以进行写入/接受,然后加锁,找到对应的 channel ,就执行对应操作,然后解锁,或有 close 的channel也会退出
参考
由浅入深聊聊Golang中select的实现机制
golang select底层原理
深入golang -- select
图解Go中select语句的底层原理