4

我正在尝试使用https://github.com/klkblake/Go-SDL在 go 中编写 SDL 应用程序。
我创建了计时器来调用它的绘图功能:

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")

select的默认分支中——代码开始按我的意愿工作(在窗口中绘制一些东西);如果我再次删除 println 它就不会画任何东西。 我究竟做错了什么?为什么会有这样的select行为?


嗯...最简单的测试用例是:

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
    }
}
4

2 回答 2

8

至于您的示例,您的循环是一个繁忙的循环,不断地遇到问题default:。go 中的调度程序是协作的,并且由于您处于忙碌的循环中,因此运行 Ticker 的 go 例程将永远不会被安排运行,因此永远不会在通道上发送任何内容。即使您的default:案例不为空,但会进行纯计算,情况也会如此 - 从不进行任何调用 schudler 的调用。

但是,当您执行以某种形式调用 go 调度程序的其他操作时,例如执行 I/O ,调度程序将给 Ticker 一个运行的机会。

您可以导入运行时包并执行

default:
    runtime.Gosched()

使调度程序运行,这不会饿死 Ticker 去例程。

我不确定这如何导致您在运行 SDL 时遇到问题,因为这很可能涉及 I/O 或其他触发调度程序的东西

于 2012-10-14T18:50:14.157 回答
6

请参阅golang:除非我添加了 fmt.Print(),否则带有 select 的 goroute 不会停止

长话短说,由于默认情况,并且因为您的 GOMAXPROCS 可能设置为 1(默认值),它永远不会安排 goroutine 完成其工作。有很多选项可以解决这个问题,具体取决于您的需要(默认睡眠,选择而不是默认的 time.After() 通道,调用 runtime.Gosched() 等)。

添加 fmt.Print 使其工作,因为 - 我的猜测,不确定 - 它涉及 io 并在内部导致 Gosched() (或者类似 Phlip 在相关问题中的答案,我刚刚读过它)。

于 2012-10-14T18:51:57.413 回答