select的奇怪行为(不允许其他goroutines运行)

Bad*_*ptr 4 go

我正在尝试使用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)

nos*_*nos 8

至于你的例子,你的循环是一个繁忙的循环,不断打击default:案例.go中的调度程序是合作的,并且由于您处于繁忙的循环中,运行Ticker的go例程将永远不会被安排运行,因此从不在通道上发送任何内容.即使你的default:情况不是空的,也会这样,但是做纯计算 - 永远不会进行任何调用schudler的调用.

但是,当您执行其他某种形式的调用go调度程序时,例如执行I/O时,调度程序将为Ticker提供运行的机会.

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

default:
    runtime.Gosched()
Run Code Online (Sandbox Code Playgroud)

使调度程序运行,这不会使Ticker go例程挨饿.

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


mna*_*mna 6

golang:goroute with select不会停止,除非我添加了fmt.Print()

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

添加fmt.Print使它工作,因为 - 我的猜测,不确定 - 它涉及io和内部导致Gosched()(在相关问题中,或者像Phlip的回答,我只是阅读它).