select的行为异常(不允许其他goroutine运行)

我正在尝试使用https://github.com/klkblake/Go-SDL编写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

    }

}


慕仙森
浏览 185回答 2
2回答

一只名叫tom的猫

请参阅golang:带有select的goroute不会停止,除非我添加了fmt.Print()长话短说,由于使用默认情况,并且因为您的GOMAXPROCS可能设置为1(默认值),所以它永远不会安排goroutine进行工作。根据您的需要,有很多选项可以解决此问题(默认情况下为sleep,select中的time.After()通道而不是默认通道,对runtime.Gosched()的调用等)。添加fmt.Print使其能够工作是因为-我的猜测(不确定)-它涉及io并在内部导致Gosched()(在相关问题中类似于Phlip的答案,我只是读过它)。

白衣染霜花

就您的示例而言,您的循环是一个繁忙的循环,不断遇到麻烦default:。go中的调度程序是协作的,并且由于您处于繁忙的循环中,因此运行Ticker的go例程将永远不会被调度运行,因此永远不会在通道上发送任何内容。即使您的default:情况不为空,而是进行纯计算-绝不会进行任何调用schudler的调用,情况就是如此。但是,当您执行某种以某种形式调用go调度程序的操作(例如,执行I / O时),调度程序将为代码行提供运行的机会。您可以导入运行时包并执行default: &nbsp;&nbsp;&nbsp;&nbsp;runtime.Gosched()使调度程序运行,这不会使Ticker go例程陷入饥饿。我不确定这将如何导致您在运行SDL时遇到的问题,因为这很可能涉及I / O或其他触发调度程序的问题
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go