简体   繁体   English

致命错误:所有 goroutines 都睡着了 - 死锁 | Go例程

[英]fatal error: all goroutines are asleep - deadlock | Go Routine

The problem is that both the goOne and goTwo functions are sending values to the channels ch1 and ch2 respectively, but there is no corresponding receiver for these values in the main function. This means that the channels are blocked and the program is unable to proceed.问题是 goOne 和 goTwo 函数都分别向通道 ch1 和 ch2 发送值,但是在主 function 中没有这些值的相应接收器。这意味着通道被阻塞,程序无法继续。 As a result, the select statement in the main function is unable to read from the channels, so it always executes the default case.导致main function中的select语句无法从通道读取,所以一直执行default case。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    ch1 := make(chan string)
    ch2 := make(chan string)

    wg.Add(2)
    go goOne(&wg, ch1)
    go goTwo(&wg, ch2)

    select {
    case <-ch1:
        fmt.Println(<-ch1)
        close(ch1)

    case <-ch2:
        fmt.Println(<-ch2)
        close(ch2)

    default:
        fmt.Println("Default Case")
    }
    wg.Wait()

}

func goTwo(wg *sync.WaitGroup, ch2 chan string) {
    ch2 <- "Channel 2"
    wg.Done()
}

func goOne(wg *sync.WaitGroup, ch1 chan string) {
    ch1 <- "Channel 1"
    wg.Done()
}

Output: Output:

Default Case
fatal error: all goroutines are asleep - deadlock!

goroutine 1 \[semacquire\]:
sync.runtime_Semacquire(0xc000108270?)
/usr/local/go/src/runtime/sema.go:62 +0x25
sync.(\*WaitGroup).Wait(0x4b9778?)
/usr/local/go/src/sync/waitgroup.go:139 +0x52
main.main()
/home/nidhey/Documents/Go_Learning/goroutines/select.go:29 +0x2af

goroutine 6 \[chan send\]:
main.goOne(0x0?, 0x0?)
/home/nidhey/Documents/Go_Learning/goroutines/select.go:39 +0x28
created by main.main
/home/nidhey/Documents/Go_Learning/goroutines/select.go:14 +0xc5

goroutine 7 \[chan send\]:
main.goTwo(0x0?, 0x0?)
/home/nidhey/Documents/Go_Learning/goroutines/select.go:33 +0x28
created by main.main
/home/nidhey/Documents/Go_Learning/goroutines/select.go:15 +0x119\```

I'm looking for a different pattern such as select to handle the case when the channels are blocked.我正在寻找一种不同的模式,例如 select 来处理通道被阻塞的情况。

To fix the issue, I've added a <-ch1 or <-ch2 in the main function after wg.Wait() to receive the values sent to the channels and unblock them为了解决这个问题,我在 wg.Wait() 之后的主 function 中添加了 <-ch1 或 <-ch2 以接收发送到通道的值并取消阻止它们

It's not entirely clear what you want to do.目前还不完全清楚你想做什么。 If you want to wait for both goroutines to complete their work and get the result of their work into the channel, you don't need a weight group (because it won't be reached).如果你想等待两个 goroutines 完成他们的工作并将他们的工作结果放入通道,你不需要权重组(因为它不会被达到)。

You can do something like this.你可以这样做。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go goOne(ch1)
    go goTwo(ch2)

    for {
        select {
        case v := <-ch1:
            fmt.Println("Done ch1:", v)
            ch1 = nil
        case v := <-ch2:
            fmt.Println("Done ch2:", v)
            ch2 = nil
        case <-time.After(time.Second):
            fmt.Println("I didn't get result so lets skip it!")
            ch1, ch2 = nil, nil
        }
        if ch1 == nil && ch2 == nil {
            break
        }
    }
}

func goTwo(ch chan string) {
    ch <- "Channel 2"
}

func goOne(_ chan string) {
    //ch1 <- "Channel 1"
}

Firstly you have a race condition in that your channel publishing goroutines will probably not have been started by the time you enter the select statement, and it will immediately fall through to the default.首先,你有一个竞争条件,因为当你输入 select 语句时,你的频道发布 goroutines 可能还没有启动,它会立即进入默认状态。

But assuming you resolve this (eg with another form of semaphore) you're on to the next issue - your select statement will either get chan1 or chan2 message, then wait at the bottom of the method, but since it is no longer in the select statement, one of your messages won't have arrived and you'll be waiting forever.但是假设您解决了这个问题(例如,使用另一种形式的信号量),您将进入下一个问题 - 您的 select 语句将获得 chan1 或 chan2 消息,然后在方法的底部等待,但由于它不再在select 声明,您的一条消息不会到达,您将永远等待。

You'll need either a loop (twice in this case) or a receiver for both channels running in their own goroutines to pick up both messages and complete the waitgroup.您需要一个循环(在本例中为两次)或一个接收器,用于在各自的 goroutine 中运行的两个通道,以获取这两个消息并完成等待组。

But in any case - as others have queried - what are you trying to achieve?但无论如何 - 正如其他人所质疑的那样 - 你想要达到什么目的?

You can try something like iterating over a single channel (assuming both channels return the same type of data) and then count in the main method how many tasks are completed.您可以尝试在单个通道上迭代(假设两个通道返回相同类型的数据),然后在 main 方法中计算完成了多少任务。 Then close the channel once all the tasks are done.然后在所有任务完成后关闭通道。 Example:例子:

package main

import (
    "fmt"
)

func main() {
    ch := make(chan string)

    go goOne(ch)
    go goTwo(ch)
    doneCount := 0

    for v := range ch {
        fmt.Println(v)
        doneCount++
        if doneCount == 2 {
            close(ch)
        }
    }
}

func goTwo(ch chan string) {
    ch <- "Channel 2"
}

func goOne(ch chan string) {
    ch <- "Channel 1"
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM