致命错误:所有 goroutine 在写入多个通道时都处于休眠状态

问题描述 投票:0回答:2

我刚刚开始学习 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)
}
go goroutine
2个回答
0
投票

你在这里混合了很多东西。

第一次死锁

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")
}

0
投票
evenChannel := make(chan int)

您的问题出在您的渠道上。两者都是阻塞通道(无维度),这意味着在您向其中推送一个值后,它将阻塞直到读取该值。在从频道中读取内容之前,将其与您的

wg.Wait()
结合起来,就会陷入僵局。

试试这个; https://go.dev/play/p/pnK7_BsQdQz

这样我们就可以通过范围表达式将通道的检查留在循环附近,等待组正在检查三个 goroutine 中的每一个是否完成。

© www.soinside.com 2019 - 2024. All rights reserved.