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

标签 go

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

selectdefault 分支中——代码开始按我希望的方式工作(在窗口中绘制一些东西);如果我再次删除 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
    }
}

最佳答案

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

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

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

default:
    runtime.Gosched()

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

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

关于go - select 的奇怪行为(不允许其他 goroutines 运行),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12884849/

相关文章:

json - golang 中的 interface{} 到 [] 字节转换

logging - GO lang日志包的局限性

postgresql - 为什么 Go 将 Postgresql 数字和小数列视为 []uint8?

go - fmt.Println与os.Stdout.Write

go - 如何将字节数组传递给 HyperLedger Fabric 中的链码

sql - 如何在 Golang 中将 *sql.Rows 转换为类型化的 JSON

go - 在 Go 中解析 JSON Web token 声明

go - 如何在 Go 中获取系统信息?

go - 在 golang 中访问指针

go - 将 base64 字符串转换为 JPG