我正在尝试使用https://github.com/klkblake/Go-SDL编写SDL应用程序.
我创建了计时器来调用draw函数:
render_timer := time.NewTicker(time.Second / 60)
Run Code Online (Sandbox Code Playgroud)
事件循环中的某个地方:
for running == true {
[...]
[process sdl events]
[...]
select {
case <-render_timer.C:
call_my_draw_function()
default:
some_default_actions()
}
[...]
}
Run Code Online (Sandbox Code Playgroud)
如果我在编译此代码后运行程序,则屏幕上不会显示任何内容.但如果我只是放置:
fmt.Println("default")
Run Code Online (Sandbox Code Playgroud)
在select的默认分支中- 代码开始按照我想要的方式工作(在窗口中绘制内容); 如果我删除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
}
}
Run Code Online (Sandbox Code Playgroud)
至于你的例子,你的循环是一个繁忙的循环,不断打击default:
案例.go中的调度程序是合作的,并且由于您处于繁忙的循环中,运行Ticker的go例程将永远不会被安排运行,因此从不在通道上发送任何内容.即使你的default:
情况不是空的,也会这样,但是做纯计算 - 永远不会进行任何调用schudler的调用.
但是,当您执行其他某种形式的调用go调度程序时,例如执行I/O时,调度程序将为Ticker提供运行的机会.
您可以导入运行时包并执行
default:
runtime.Gosched()
Run Code Online (Sandbox Code Playgroud)
使调度程序运行,这不会使Ticker go例程挨饿.
我不确定这会导致运行SDL时遇到的问题,因为这很可能涉及I/O或其他触发调度程序的问题
看golang:goroute with select不会停止,除非我添加了fmt.Print()
长话短说,由于默认情况,并且因为您的GOMAXPROCS可能设置为1(默认值),它从不安排goroutine来完成其工作.有很多选项可以解决这个问题,具体取决于您的需求(默认情况下的睡眠,select中的time.After()通道而不是默认,调用runtime.Gosched()等).
添加fmt.Print使它工作,因为 - 我的猜测,不确定 - 它涉及io和内部导致Gosched()(在相关问题中,或者像Phlip的回答,我只是阅读它).
归档时间: |
|
查看次数: |
354 次 |
最近记录: |