我有一个goroutine正在无限播放play()
的某些音频。为了保持play()
的生命,我让调用函数随后运行了无限循环。
出乎意料的是,准系统循环似乎并没有让该函数无限地发挥作用,而我对原因感到茫然。但是,如果我将一个简单的time.Sleep(time.Second)
添加到for循环的主体中,它似乎可以无限运行。知道为什么吗?
可视化:
func PlaysForAFewSeconds() {
go play()
for {
}
}
^播放了几秒钟,但从未中断
func PlaysForever() {
go play()
for {
time.Sleep(time.Second)
}
}
^永远玩。
我猜想这与play()
的实现方式有关,但我希望这是一个普遍的问题,足以使人们认识到这种症状。
谢谢。
答案 0 :(得分:0)
static async Task Main(string[] args)
{
var tasks = Enumerable.Range(0, 3).Select(x => Task.Run(() =>
{
Counter();
}));
await Task.WhenAll(tasks);
Console.ReadLine();
}
public static void Counter()
{
while (true)
{
for (int i = 0; i < 1000000; i++)
{
Console.WriteLine(i);
}
}
}
生成的程序集是for { }
,其中jmp self
是self
指令的位置。换句话说,CPU将尽可能快地继续运行jmp
指令。 CPU每秒可以运行 n 条指令,这是无用的jmp
还是实际有用的指令都没关系。
这被称为“忙等待”或“旋转锁定”,并且此行为并非特定于Go。大多数(所有?)编程语言的行为都是这样。
此类循环有一些用途,但在Go中,它们通常可以用通道替换:
jmp
从通道(// 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
}
}
)读取的操作被阻止,并且不使用任何CPU。我使用了一个空的匿名结构,它看起来有点丑陋,因为它没有分配任何内存。