有 vs 没有 time.Sleep() 的无限循环
Infinite looping with vs without time.Sleep()
我有一个 goroutine 可以无限播放一些音频 play()
。为了让 play()
保持活动状态,我在调用函数 运行 之后设置了一个无限循环。
出乎意料的是,准系统循环似乎并没有让函数无限播放,我不知道为什么。但是,如果我将一个简单的 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 只会尽可能快地保持 运行ning jmp
指令。 CPU 每秒可以 运行 n 条指令,不管这是无用的 jmp
还是实际有用的指令。
这被称为 "busy wait" 或 "spin lock",并且此行为并非特定于 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。我使用了一个空的匿名结构,它看起来有点难看,因为它没有分配任何内存。
我有一个 goroutine 可以无限播放一些音频 play()
。为了让 play()
保持活动状态,我在调用函数 运行 之后设置了一个无限循环。
出乎意料的是,准系统循环似乎并没有让函数无限播放,我不知道为什么。但是,如果我将一个简单的 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 只会尽可能快地保持 运行ning jmp
指令。 CPU 每秒可以 运行 n 条指令,不管这是无用的 jmp
还是实际有用的指令。
这被称为 "busy wait" 或 "spin lock",并且此行为并非特定于 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。我使用了一个空的匿名结构,它看起来有点难看,因为它没有分配任何内存。