go - 无限循环有 vs 没有 time.Sleep()
问题描述
我有一个 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
,其中self
是jmp
指令的位置。换句话说,CPU 将jmp
尽可能快地保持运行指令。CPU每秒可以运行n条指令,不管这是一条无用jmp
的指令还是一条真正有用的指令。
这被称为“忙等待”或“自旋锁”,这种行为并不是 Go 特有的。大多数(全部?)编程语言的行为都是这样的。
这种循环有一些用途,但在 Go 中,它们通常可以用通道替换:
// 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
}
}
从通道 ( ) 读取<-wait
是阻塞的并且不使用任何 CPU。我使用了一个空的匿名结构,它看起来有点难看,因为它没有分配任何内存。
推荐阅读
- postgresql - 使用 slick 在 postgres 更新中避免竞争条件
- prolog - heapify prolog 实现
- azure - Azure API 管理 - 确定响应是否来自缓存
- google-sheets - 公式未提供准确的结果
- chrome-custom-tabs - 受信任的 Web 活动和 Bubblewrap 强制渲染引擎 (Chromium/firefox/geko)
- sql - 多个where子句的SQL查询
- android - 为什么 RecyclerView 项目在点击两次后才改变背景颜色?
- python - 如何使用 Python PDB 进入生成器函数?
- ios - Xcode 作为 macOS 打开一个 iOS 项目
- wso2 - WSO2 Identity Server 5.10.0 - 无法实现基于 EmailOTP 的 MFA