关闭停止通道不会停止 goroutines
Closing stop channel does not stop goroutines
简介:
我刚开始学习Go语言,已经到了关于并发的课程。
我为自己发明了一个小任务来尝试实现我学到的关于关闭 goroutines 的知识。
问题:
如果我们关闭通道,它的 case
将始终在 select
语句中被选中,这是向所有 goroutines 广播取消信号的好方法。
下面我有 2 个 goroutine 和一个从未收到的 quit
通道。
Playground 上的代码超时。
如果我注释掉 goroutine 中的 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()
}
这段代码在现实生活中没有问题;它只是与 playground 的 "fake time" 不兼容,因为 positive_numbers
和 negative_numbers
不阻塞,并且 运行time 无法决定每个迭代有多少次到达 运行 在 Sleep
到期之前(基本上,打印占用零模拟挂钟时间,因此它们会尝试产生无限输出,并且您达到操场上的 CPU 使用限制而根本没有提前挂钟时间).在真实的机器上,你只能在有限的时间内打印有限的输出,你会得到合理的行为。
在 playground 中,如果在每次打印后添加类似 time.Sleep(time.Millisecond)
的内容,就会强制假时钟向前移动,程序也会终止。
简介:
我刚开始学习Go语言,已经到了关于并发的课程。
我为自己发明了一个小任务来尝试实现我学到的关于关闭 goroutines 的知识。
问题:
如果我们关闭通道,它的 case
将始终在 select
语句中被选中,这是向所有 goroutines 广播取消信号的好方法。
下面我有 2 个 goroutine 和一个从未收到的 quit
通道。
Playground 上的代码超时。
如果我注释掉 goroutine 中的 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()
}
这段代码在现实生活中没有问题;它只是与 playground 的 "fake time" 不兼容,因为 positive_numbers
和 negative_numbers
不阻塞,并且 运行time 无法决定每个迭代有多少次到达 运行 在 Sleep
到期之前(基本上,打印占用零模拟挂钟时间,因此它们会尝试产生无限输出,并且您达到操场上的 CPU 使用限制而根本没有提前挂钟时间).在真实的机器上,你只能在有限的时间内打印有限的输出,你会得到合理的行为。
在 playground 中,如果在每次打印后添加类似 time.Sleep(time.Millisecond)
的内容,就会强制假时钟向前移动,程序也会终止。