Go lang 多路复用所有 goroutines 都睡着了 - 死锁

标签 go

我想使用多个 go 例程返回 channel 创建一个扇入函数,这是我的代码。

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\n", msg, i)
        time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
    }
    return c
}

但是我运行上面的代码后出现错误

all goroutines are asleep - deadlock

我已经尝试关闭 channel ,但它仍然给我错误。我曾尝试将无聊的返回 channel 分配给 Joe 和 Ann,然后将这些 channel 传递给多路复用的通话功能,但仍然没有成功。我是新来学习 channel 的,对这个概念不是很清楚。

最佳答案

代替 WaitGroup ,您可以使用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

编辑:

在您给出的示例中,boring 函数不使用 goroutine 重复发送 channel ,这将永远阻塞,因为: 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.

此外,wg.Done() 需要成为 goroutine 的一部分。

我通过进行上述更改使其正常工作:https://play.golang.org/p/YN0kfBO6iT

关于Go lang 多路复用所有 goroutines 都睡着了 - 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44487887/

相关文章:

json - 如何创建json数组并插入json对象

string - 如何从字符串中删除尾随 "\r\n"

go - func中的空返回与golang中的返回值

string - 有什么方法可以在打印语句中没有 7、-48 .... 等的情况下以漂亮的方式显示输出?

networking - Go 中的服务器,重定向到标准输出

go - 在 Go 中,我可以返回满足接口(interface)但不访问该接口(interface)的结构吗?

go - C++ 中的 Const 引用和 Golang 中的等价物

go - 从 Golang 中的结构更新值

performance - 为什么我的 GAE 应用程序提供静态文件的延迟如此之高?

unit-testing - 如何在 golang 中测试 io.writer?