duanche4578 2017-06-11 19:29
浏览 41
已采纳

Go语言多路复用所有goroutine都处于睡眠状态-死锁

I wants to create a fan-in function using multiple go routines returning channel here is my code.

package main

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

var wg, wg2 sync.WaitGroup

func main() {
    final := talk(boring("Joe"), boring("Ann"))
    for i := 0; i < 10; i++ {
        fmt.Println(<-final)
    }
    fmt.Println("You are both boring I'm leaving")
}

func talk(input1, input2 <-chan string) <-chan string {
    out := make(chan string)
    go func() {
        wg.Add(1)
        for {
            out <- <-input1
        }
    }()
    go func() {
        wg.Add(1)
        for {
            out <- <-input2
        }
    }()
    wg.Done()
    close(out)
    return out
}

func boring(msg string) <-chan string {
    c := make(chan string)
    for i := 0; i < 5; i++ {
        c <- fmt.Sprintf("%s%d
", msg, i)
        time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
    }
    return c
}

But I got an error after running above code

all goroutines are asleep - deadlock

I have tried to close channels but still it is giving me the error. I have tried to assign boring returned channels to Joe and Ann and then pass those channels to talk function for multiplexing still no success. I am new to go learning channels not clear on this concept.

  • 写回答

2条回答 默认 最新

  • douwen1937 2017-06-11 20:01
    关注

    Instead of wait groups, you can use select: https://tour.golang.org/concurrency/5

    The select statement lets a goroutine wait on multiple communication operations.

    A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready.

    package main
    
    import (
        "fmt"
        "math/rand"
        "time"
    )
    
    func main() {
        final := talk(boring("Joe"), boring("Ann"))
        for i := 0; i < 10; i++ {
            fmt.Println(<-final)
        }
        fmt.Println("You are both boring I'm leaving")
    }
    
    func talk(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
    }
    
    func boring(msg string) <-chan string {
        c := make(chan string)
        go func() {
            for i := 0; i < 5; i++ {
                c <- fmt.Sprintf("%s: %d", msg, i)
                time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
            }
        }()
        return c
    }
    

    Try it on Playground

    Edit:

    In your given example, boring function doesn't use goroutine for repeated send over channel which will block forever, because: https://tour.golang.org/concurrency/2

    By default, sends and receives block until the other side is ready. This allows goroutines to synchronize without explicit locks or condition variables.

    Also, wg.Done() needs to be part of goroutine.

    I got it working by doing above changes: https://play.golang.org/p/YN0kfBO6iT

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥20 求数据集和代码#有偿答复
  • ¥15 关于下拉菜单选项关联的问题
  • ¥20 java-OJ-健康体检
  • ¥15 rs485的上拉下拉,不会对a-b<-200mv有影响吗,就是接受时,对判断逻辑0有影响吗
  • ¥15 使用phpstudy在云服务器上搭建个人网站
  • ¥15 应该如何判断含间隙的曲柄摇杆机构,轴与轴承是否发生了碰撞?
  • ¥15 vue3+express部署到nginx
  • ¥20 搭建pt1000三线制高精度测温电路
  • ¥15 使用Jdk8自带的算法,和Jdk11自带的加密结果会一样吗,不一样的话有什么解决方案,Jdk不能升级的情况
  • ¥15 画两个图 python或R