The Go select https://golang.org/ref/spec#Select_statements声明不偏向任何(现成的)案例。引用规范:
如果一个或多个通信可以继续进行,则通过均匀伪随机选择。否则,如果存在默认情况,则选择该情况。如果不存在默认情况,则“select”语句将阻塞,直到至少其中一个通信可以继续进行。
如果可以进行多个通信,则随机选择一个。这不是完美的随机分布,规范也不能保证这一点,但它是随机的。
你所体验到的是 Go Playground 的结果GOMAXPROCS=1
(你可以在这里验证 https://play.golang.org/p/GIIyXQb643)并且 goroutine 调度程序不是抢占式的。这意味着默认情况下 goroutine 不是并行执行的。如果遇到阻塞操作(例如,从网络读取,或尝试在阻塞的通道上接收或发送),则将 goroutine 置于停放状态,而另一个准备运行的 goroutine 将继续运行。
而且由于您的代码中没有阻塞操作,因此 goroutine 可能不会被放入公园,并且可能只有您的“生产者”goroutines 之一会运行,而另一个可能不会被调度(永远)。
在我的本地计算机上运行您的代码GOMAXPROCS=4
,我得到了非常“现实”的结果。运行几次,输出:
finish one acount, bcount 1000 901
finish one acount, bcount 1000 335
finish one acount, bcount 1000 872
finish one acount, bcount 427 1000
如果您需要优先考虑单个案例,请查看以下答案:强制 go select 语句的优先级 https://stackoverflow.com/questions/46200343/force-priority-of-go-select-statement/46202533#46202533
默认行为select
不保证同等优先级,但平均而言会接近它。如果您需要保证同等优先级,那么您不应该使用select
,但是您可以从 2 个通道执行一系列 2 个非阻塞接收,如下所示:
for {
select {
case <-chana:
acount++
default:
}
select {
case <-chanb:
bcount++
default:
}
if acount == 1000 || bcount == 1000 {
fmt.Println("finish one acount, bcount", acount, bcount)
break
}
}
如果两个通道都提供值,则上述 2 个非阻塞接收将以相同的速度(具有相同的优先级)耗尽 2 个通道,如果一个通道没有提供值,则另一个通道将不断接收而不会出现延迟或阻塞。
关于这一点需要注意的一件事是,如果none的通道提供任何要接收的值,这基本上将是一个“繁忙”循环,因此消耗计算能力。为了避免这种情况,我们可能会检测到没有任何通道准备就绪,并且then use a select
语句与两个接收,然后将阻塞,直到其中之一准备好接收,不浪费任何 CPU 资源:
for {
received := 0
select {
case <-chana:
acount++
received++
default:
}
select {
case <-chanb:
bcount++
received++
default:
}
if received == 0 {
select {
case <-chana:
acount++
case <-chanb:
bcount++
}
}
if acount == 1000 || bcount == 1000 {
fmt.Println("finish one acount, bcount", acount, bcount)
break
}
}
有关 goroutine 调度的更多详细信息,请参阅以下问题:
Go运行时使用的线程数 https://stackoverflow.com/questions/39245660/number-of-threads-used-by-go-runtime/39246575#39246575
Goroutines 8kb 和 Windows 操作系统线程 1 mb https://stackoverflow.com/questions/30073441/goroutines-8kb-and-windows-os-thread-1-mb/30074921#30074921
为什么golang写文件时很多goroutine被阻塞却没有创建很多线程? https://stackoverflow.com/questions/28186361/why-does-it-not-create-many-threads-when-many-goroutines-are-blocked-in-writing/28186656#28186656