为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕仙森 2021-05-14 14:09:01
我正在尝试使用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 mainimport ("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    }}
查看完整描述

2 回答

?
一只名叫tom的猫

TA贡献1906条经验 获得超3个赞

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

长话短说,由于使用默认情况,并且因为您的GOMAXPROCS可能设置为1(默认值),所以它永远不会安排goroutine进行工作。根据您的需要,有很多选项可以解决此问题(默认情况下为sleep,select中的time.After()通道而不是默认通道,对runtime.Gosched()的调用等)。

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


查看完整回答
反对 回复 2021-05-17
?
白衣染霜花

TA贡献1796条经验 获得超10个赞

就您的示例而言,您的循环是一个繁忙的循环,不断遇到麻烦default:。go中的调度程序是协作的,并且由于您处于繁忙的循环中,因此运行Ticker的go例程将永远不会被调度运行,因此永远不会在通道上发送任何内容。即使您的default:情况不为空,而是进行纯计算-绝不会进行任何调用schudler的调用,情况就是如此。

但是,当您执行某种以某种形式调用go调度程序的操作(例如,执行I / O时),调度程序将为代码行提供运行的机会。

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

default:
    runtime.Gosched()

使调度程序运行,这不会使Ticker go例程陷入饥饿。

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


查看完整回答
反对 回复 2021-05-17
  • 2 回答
  • 0 关注
  • 184 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信