让我们从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)
    }
}
}
Run Code Online (Sandbox Code Playgroud)
这有效.但是如果我不想在默认情况下打印或睡眠,但只是想保持循环呢?我试过这个:
    case <-boom:
        fmt.Println("BOOM!")
        return
    default: // Nothing here.
    }
}
}
Run Code Online (Sandbox Code Playgroud)
但它阻止了.
我在这里和那里看到一个关于goroutines调度的句子,但我不理解它们.所以我想我有两个问题:
1)为什么阻止?
2)如何在没有阻止的情况下做任何事情?
您的原始示例生成此
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
    .
    .
tick.
BOOM!
Run Code Online (Sandbox Code Playgroud)
Wheraeas 你的第二个例子产生了这个
[process took too long]
Run Code Online (Sandbox Code Playgroud)
不同之处在于您在default案例中所做的工作.一个default案例总是准备好运行,因此select其中的默认语句永远不会阻塞.第二个示例围绕循环运行,连续选择一个准备运行的分支(case或default).您现在想知道为什么计时器永远不会触发.这是因为前程序没有先发制人.因此,因为下面的循环从不执行任何IO,所以时间滴答不会触发.
for {
    select {
        // whatever
        default:
    }
}
Run Code Online (Sandbox Code Playgroud)
有很多方法可以解决这个问题.首先,你可以像在第一个例子中那样放入一些IO.或者您可以将runtime.Gosched()放入.或者您可以允许go运行时在runtime.GOMAXPROCS(2)中使用多个线程,所有这些都可以工作.
最好的办法是恕我直言完全离开了默认的声明是这样.没有默认语句的select将阻塞,直到其中一个case语句准备就绪.如果你想做一些后台处理(你在默认语句中做的那样),那么就开始一个goroutine - 这就是go go!
事实上,我在select语句中看到了很多默认问题,我很想说它们从不使用它们.
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           1461 次  |  
        
|   最近记录:  |