我正在尝试使用https://github.com/klkblake/Go-SDL编写SDL应用程序 我创建了计时器来调用draw函数:
render_timer := time.NewTicker(time.Second / 60)
事件循环中的某处:
for running == true {
[...]
[process sdl events]
[...]
select {
case <-render_timer.C:
call_my_draw_function()
default:
some_default_actions()
}
[...]
}
如果我在编译此代码后运行程序,则屏幕上不会显示任何内容。但如果我只是放置:
fmt.Println("default")
选择的默认分支中的- 代码开始按我的意愿工作(在窗口中绘制内容);如果我删除println它再次不绘制任何东西 我究竟做错了什么?为什么会出现选择的行为?
嗯...最简单的测试用例是:
package main
import (
"fmt"
"time"
)
func main() {
rt := time.NewTicker(time.Second / 60)
for {
select {
case <-rt.C:
fmt.Println("time")
default:
}
time.Sleep(1) // without this line 'case <-rt.C' is never executed
}
}
答案 0 :(得分:7)
至于你的例子,你的循环是一个繁忙的循环,经常遇到default:
的情况。 go中的调度程序是合作的,并且由于您处于繁忙的循环中,运行Ticker的go例程将永远不会被安排运行,因此从不在通道上发送任何内容。即使你的default:
大小写不是空的,但是进行纯计算 - 从不进行任何调用schudler的调用,情况也是如此。
然而,当你做某事时,以某种形式调用go调度程序,例如执行I / O时,调度程序将为Ticker提供运行的机会。
您可以导入运行时包并执行
default:
runtime.Gosched()
使调度程序运行,这不会使Ticker go例程挨饿。
我不确定这会导致运行SDL时遇到的问题,因为这很可能涉及I / O或触发调度程序的其他内容
答案 1 :(得分:6)
请参阅golang: goroute with select doesn't stop unless I added a fmt.Print()
长话短说,由于默认情况,并且因为您的GOMAXPROCS可能设置为1(默认值),所以它从不安排goroutine来完成其工作。有很多选项可以解决这个问题,具体取决于您的需求(默认情况下的睡眠,select中的time.After()通道而不是默认值,调用runtime.Gosched()等。)
添加fmt.Print使它工作,因为 - 我的猜测,不确定 - 它涉及io和内部导致Gosched()(在相关问题中,或者像Phlip的回答,我只是阅读它。)