Go 当没有通道准备好读取时,如何不执行任何操作?

Go 当没有通道准备好读取时,如何不执行任何操作?,go,channel,Go,Channel,让我们以GoTour中的这个例子为例,因为它说明了我仅在存在事件时处理SDL事件的问题 package main import ( "fmt" "time" ) func main() { tick := time.Tick(1e8) boom := time.After(5e8) for { select { case <-tick: fmt.Println("tick.") case <-boom: fmt.Printl

让我们以GoTour中的这个例子为例,因为它说明了我仅在存在事件时处理SDL事件的问题

package main

import (
"fmt"
"time"
)

func main() {
tick := time.Tick(1e8)
boom := time.After(5e8)
for {
    select {
    case <-tick:
        fmt.Println("tick.")
    case <-boom:
        fmt.Println("BOOM!")
        return
    default:
        fmt.Println("    .")
        time.Sleep(5e7)
    }
}
}
主程序包
进口(
“fmt”
“时间”
)
func main(){
勾号:=时间。勾号(1e8)
动臂:=时间后(5e8)
为了{
挑选{
case产生了这种情况

    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
BOOM!
[process took too long]
Wheraeas生产这个

    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
BOOM!
[process took too long]
不同之处在于您在
default
案例中所做的操作。
default
案例始终可以运行,因此带有default语句的
select
不会阻塞。第二个示例在循环中连续运行,选择一个分支(case或default)准备好运行了。您现在想知道为什么计时器从不触发。这是因为go例程不是预先安排的。因此,因为下面的循环从不执行任何IO,所以时间滴答从不触发

for {
    select {
        // whatever
        default:
    }
}
有很多方法可以解决这个问题。首先,你可以像你在第一个例子中那样放入一些IO。或者你可以放入一个。或者你可以允许go运行时使用多个线程,所有这些都可以工作

IMHO最好的方法是完全省略默认语句。没有默认语句的select将阻塞,直到其中一个case语句准备就绪。如果您想进行一些后台处理(您在默认语句中所做的),则启动goroutine-这就是正确的方法


事实上,我在select语句中看到了太多关于默认的问题,我很想说永远不要使用它们。

我偶尔使用默认值,所以我认为说永远不要使用它们是不公平的。问题不是select语句中的默认子句造成的,而是对Goroutine如何工作的误解。即使在恩,stackoverflow中的问题证明没有select语句。真正的问题是有一个繁忙的循环。这是一个游戏循环。运行物理,更新屏幕,并处理事件(如果有)。如果我在另一个goroutine中泵送事件,那将造成混乱,因为它将发生在物理或渲染期间。也就是说为什么我不想阻止。Gosched似乎是一条路。Gosched成功了。我不明白GOROUTIES有点像协同程序:协作。在python中,我必须屈服,我明白Gosched就是这样做的。Gosched几乎总是一个你做错了事情的标志。这是我第二次听到这样的话“这是一个游戏循环“作为写繁忙循环的借口。你真的不需要这样做。睡眠几乎总是一个坏主意。你有一个售票员在频道里吐东西和工作请求。你可以一直等到有工作,并保持一个非常紧凑的日程安排。这篇演讲描述了为什么要这样做以及如何做: