go - 有 time.Sleep() 的无限循环与没有 time.Sleep() 的无限循环

标签 go goroutine

我有一个 goroutine 正在无限地播放一些音频 play() 。为了保持play()活着,我已经让调用函数运行了一个无限的 for 循环。

出乎意料的是,准系统循环似乎并没有让该函数无限地运行,我不知道为什么。但是,如果我添加一个简单的 time.Sleep(time.Second)进入 for 循环的主体,它似乎无限运行。知道为什么吗?

可视化:

func PlaysForAFewSeconds() {
    go play()
    for {
    }
}

^播放几秒钟但从未中断

func PlaysForever() {
    go play()
    for {
        time.Sleep(time.Second)
    }
}

^ 永远播放。

我猜这与 play() 的方式有关。已实现,但我希望这是一个足够常见的问题,有人能认识到这种症状。 谢谢。

最佳答案

装配for { }生成是 jmp self ,其中selfjmp 的位置操作说明。换句话说,CPU 将继续运行 jmp尽可能快地发出指示。 CPU 每秒可以运行 n 条指令,如果这是无用的也没关系 jmp或实际有用的说明。

这称为“忙等待”或“自旋锁”,这种行为并非 Go 所特有。大多数(全部?)编程语言的行为都是这样的。

此类循环有一些用途,但在 Go 中它们通常可以用 channel 替换:

// Simulate a function that takes 1s to complete.
func play(ch chan struct{}) {
    fmt.Println("play")
    time.Sleep(1 * time.Second)
    ch <- struct{}{}
}

func PlaysForAFewSeconds() {
    wait := make(chan struct{})
    go play(wait)
    <-wait
}

func PlaysForever() {
    wait := make(chan struct{})
    for {
        go play(wait)
        <-wait
    }
}

从 channel ( <-wait ) 读取数据是阻塞的,并且不使用任何 CPU。我使用了一个空的匿名结构,它看起来有点难看,因为它不分配任何内存。

关于go - 有 time.Sleep() 的无限循环与没有 time.Sleep() 的无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55858835/

相关文章:

linux - 回答 golang 中的密码 shell 提示

ssl - 在长轮询期间刷新 NginX 的 SSL 缓冲区

sockets - 检索确切的连接 - tcp 套接字 - channel - goroutine

go - 为什么此代码会产生错误?

curl - 如何接受来自 Go 的 POST 请求并将输出写入文件?

encoding - 如何编码/解码空字符串

go - 在外部包中注册 Golang gorilla/mux 路由

go - 通过 channel 在 Go 中进行通信

go - 在另一个例程中调用SetReadDeadline是否正确?

go - 如何在运行例程时将值分配给结构?