Go是否保证先阻塞在channel上的goroutine会优先获取到数据?
Go channel阻塞goroutine的接收优先级问题
核心结论
先阻塞在channel上的goroutine不一定会优先获取到数据,你给出的代码行为不存在官方保证,第20行启动的goroutine也存在拿到数据的可能性,依赖接收顺序的逻辑是不严谨的。
具体说明
- 语言规范层面
Go官方语言规范从未对channel接收者的调度优先级做出任何强制性约定,所有依赖goroutine接收channel顺序的代码都不符合语言规范的可移植性要求,可能在不同编译器、不同版本的Go运行时中表现不一致。
- 当前主流实现的细节
目前常用的Go官方gc编译器中,无缓冲channel的等待goroutine队列确实采用FIFO策略维护,你提供的示例代码在绝大多数场景下运行时,都会是第16行启动的goroutine先拿到数据,但这仅仅是当前版本的实现细节,不是语言层面承诺的稳定特性,不应该作为代码逻辑的依赖依据。
- 不可预测性的来源
即便当前实现是FIFO,你的代码也没有严格保障第16行的goroutine已经进入阻塞状态:
time.Sleep只是暂停main goroutine的调度,极端场景下如果系统调度出现延迟,1秒后第16行启动的goroutine还没执行到<-c的阻塞步骤,反而第20行启动的goroutine先进入等待队列,就会是后者拿到数据。如果涉及带缓冲的channel、多channel select操作,调度的不确定性会更高。
示例代码
package main import ( "time" "fmt" ) func g(c chan int) { v, ok := <-c fmt.Println(">>>", v, ok) } func main() { c := make(chan int) // Line 16 go g(c) time.Sleep(1 * time.Second) // Line 20 go g(c) c <- 233 close(c) time.Sleep(1 * time.Second) }
内容的提问来源于stack exchange,提问作者lnshi
相关产品推荐
相关产品推荐

