简介:
我刚刚开始学习Go语言,并且已经上了关于并发的课。
我为自己发明了一个小任务,试图实现我所学到的关于关闭goroutines的知识。
问题:
如果我们关闭通道,它的case
将始终在select
语句中选择,这是向所有goroutine广播取消信号的好方法。
下面我有两个goroutines和一个永远不会被接收的quit
频道。
操场上的代码超时。
如果我在goroutines中注释掉default
部分,则接收到quit
信号。
问题:
我真的不明白为什么会发生这种情况,以及如何解决它,尽管我正在努力
有人能解释一下问题出在哪里,并就如何解决提出一些建议吗
package main
import (
"fmt"
"sync"
"time"
)
func positive_numbers(quit chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
i := 1
for {
select {
case <-quit:
fmt.Println("[+]Quiting...")
return
default:
fmt.Printf("%v ", i)
i++
}
}
}
func negative_numbers(quit chan struct{}, wg *sync.WaitGroup) {
defer wg.Done()
i := -1
for {
select {
case <-quit:
fmt.Println("[-]Quiting...")
return
default:
fmt.Printf("%v ", i)
i--
}
}
}
func main() {
quit := make(chan struct{})
wg := sync.WaitGroup{} // so we can wait for all goroutines to finish
wg.Add(2)
go positive_numbers(quit, &wg)
go negative_numbers(quit, &wg)
go func(quit chan struct{}) {
defer close(quit)
time.Sleep(1 * time.Second)
}(quit)
wg.Wait()
}
此代码在现实生活中运行良好;它只是与操场上的";假时间";因为positive_numbers
和negative_numbers
不阻塞,并且运行时无法决定在Sleep
到期之前每一个的迭代次数(基本上,打印占用的模拟墙时钟时间为零,所以它们试图产生无限的输出,并且在根本不提前墙时钟时间的情况下就达到了操场CPU使用限制)。在真实的机器上,你只能在有限的时间内打印有限的输出,你会得到合理的行为。
在操场上,如果你在每次打印后添加time.Sleep(time.Millisecond)
之类的东西,你就会迫使假时钟向前移动,程序也会终止。