我刚刚开始学习 Go 例程,我试图在一个 Go 例程中写入两个通道,生成偶数和奇数,直到 50。但是,我陷入了僵局。
这是代码,我做错了什么?
package main
import (
"fmt"
"sync"
)
func generateNumbers(wg *sync.WaitGroup, evenChannel, oddChannel chan<- int) {
defer wg.Done()
for i := 1; i <= 50; i++ {
if i%2 == 1 {
oddChannel <- i
} else {
evenChannel <- i
}
}
}
func main() {
var wg sync.WaitGroup
evenChannel := make(chan int)
oddChannel := make(chan int)
wg.Add(1)
go generateNumbers(&wg, evenChannel, oddChannel)
wg.Wait()
for {
select {
case evenNum, ok := <-evenChannel:
if ok {
fmt.Println("Even Number:", evenNum)
} else {
evenChannel = nil
}
case oddNum, ok := <-oddChannel:
if ok {
fmt.Println("Odd Number:", oddNum)
} else {
oddChannel = nil
}
}
if evenChannel == nil && oddChannel == nil {
break
}
}
close(evenChannel)
close(oddChannel)
}
你在这里混合了很多东西。
第一次死锁
wg.Wait() vs oddChannel <- i
您正在等待 goRoutine 完成,并且 goRoutine 将等待直到场景主场景中的其他 goRoutine 接收到通道。
第二次僵局
在主功能上,您将关闭通道。你永远逃脱不了for循环!所以这应该是在
generateNumbers
函数上
close(evenChannel)
close(oddChannel)
最终代码:
package main
import (
"fmt"
"sync"
)
func generateNumbers(wg *sync.WaitGroup, evenChannel, oddChannel chan<- int) {
defer wg.Done()
for i := 1; i <= 50; i++ {
if i%2 == 1 {
oddChannel <- i
} else {
evenChannel <- i
}
}
close(evenChannel)
close(oddChannel)
}
func main() {
var wg sync.WaitGroup
evenChannel := make(chan int)
oddChannel := make(chan int)
wg.Add(1)
go generateNumbers(&wg, evenChannel, oddChannel)
for {
select {
case evenNum, ok := <-evenChannel:
if ok {
fmt.Println("Even Number:", evenNum)
} else {
evenChannel = nil
}
case oddNum, ok := <-oddChannel:
if ok {
fmt.Println("Odd Number:", oddNum)
} else {
oddChannel = nil
}
}
if evenChannel == nil && oddChannel == nil {
break
}
}
wg.Wait()
fmt.Println("FINISH")
}
evenChannel := make(chan int)
您的问题出在您的渠道上。两者都是阻塞通道(无维度),这意味着在您向其中推送一个值后,它将阻塞直到读取该值。在从频道中读取内容之前,将其与您的
wg.Wait()
结合起来,就会陷入僵局。
试试这个; https://go.dev/play/p/pnK7_BsQdQz
这样我们就可以通过范围表达式将通道的检查留在循环附近,等待组正在检查三个 goroutine 中的每一个是否完成。