all goroutines are asleep deadlock

不羁的心 提交于 2021-02-20 18:14:06

问题


I am trying to play around with goroutines and channel

    package main

import (
    "fmt"
    "math/rand"
    "time"
)

func boring(msg string) <-chan string {
    c := make(chan string)
    go func() {
        for i := 0; ; i++ {
            c <- fmt.Sprintf("%s %d", msg, i)
            time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
        }
    }()
    return c
}
func main() {
    c := fanInNew(boring("joe"), boring("anh"))
    for i := 0; i < 10; i++ {
        fmt.Println(<-c)
    }
    fmt.Println("You both are boring, I am leaving")
}

func fanInNew(input1, input2 <-chan string) <-chan string {
    c := make(chan string)
    for {
        select {
        case s := <-input1:
            c <- s
        case s := <-input2:
            c <- s
        }
    }
    return c
}

If i run this program it is giving me error, all goroutines are asleep, deadlock.

But If I put select inside anonymous goroutine, it works just fine. Working example:

    package main

import (
    "fmt"
    "math/rand"
    "time"
)

func boring(msg string) <-chan string {
    c := make(chan string)
    go func() {
        for i := 0; ; i++ {
            c <- fmt.Sprintf("%s %d", msg, i)
            time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
        }
    }()
    return c
}
func main() {
    c := fanInNew(boring("joe"), boring("anh"))
    for i := 0; i < 10; i++ {
        fmt.Println(<-c)
    }
    fmt.Println("You both are boring, I am leaving")
}

func fanInNew(input1, input2 <-chan string) <-chan string {
    c := make(chan string)
    go func() {
        for {
            select {
            case s := <-input1:
                c <- s
            case s := <-input2:
                c <- s
            }
        }
    }()
    return c
}

Can you please help me to understand reasoning behind it.


回答1:


The for statements loops forever, and so the <-c chan is never passed along and the chans get filled, but the main thread gets stuck waiting for c := fanInNew(a, b).

fanInNew() never returns because for loops forever (and blocks on select btw):

func fanInNew(input1, input2 <-chan string) <-chan string {
    c := make(chan string)
    for { // Loop forever and read from inputs 1 and 2
        select {
        case s := <-input1:
            c <- s
        case s := <-input2:
            c <- s            
        }
    }
    return c
}

Then in the main thread this function never returns the c chan.

func main() {
    // Never gets passed the next line
    c := fanInNew(boring("joe"), boring("anh"))
}

So you can put the for loops themselves in goroutines, as you did in the second example. Also typically goroutines should return, either because you pass a message in (such as by close()ing), or because they reach a return statement.

In any case, what you have in the 2nd example is great for demonstrating the use of anonymous closures. The chan passed into the goroutine can be returned elsewhere and enable safe message passing between threads:

c := make(chan string)
go func() {
    for {
        select {
        case s := <-input1:
            c <- s
        case s := <-input2:
            c <- s
        }
    }
}()
return c

There are a few ways of ending a for loop in an anonymous goroutine, including select on a second chan, a closing channel, which when close()ed you can return. Also, typically WaitGroups can achieve that.



来源:https://stackoverflow.com/questions/41653695/all-goroutines-are-asleep-deadlock

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!