多个 goroutines 和一个通道的死锁

我有一个我无法解决的死锁问题。


我拥有一些 url,goroutine 中的每个 url 都会给我带来足够的数据。我将这些数据放入单个通道中。但是,如果我关闭频道,程序将无法运行,如果我离开频道,则会出现打开死锁。


不知道怎么解决,求大神解答


下面我把问题简化一下


package main


import (

    "fmt"

)


type urlNumbers struct {

    url string

    numbers []int

}


func getNumbers(urls []urlNumbers) chan int {

    ch := make(chan int)


    for _, url := range urls {

        go allNumbersOfURL(url, ch)

    }


    return ch

}


func allNumbersOfURL(url urlNumbers, ch chan int) {

    for _, i := range url.numbers {

        ch <- i

    }

}


func main() {

    url1 := urlNumbers {url: "1", numbers: []int{1, 2, 3}}

    url2 := urlNumbers {url: "2", numbers: []int{4, 5, 6}}

    url3 := urlNumbers {url: "3", numbers: []int{7, 8, 9}}

    url4 := urlNumbers {url: "4", numbers: []int{10, 11, 12}}


    c := getNumbers([]urlNumbers{url1, url2, url3, url4})


    for i := range c {

        fmt.Println(i)

    }


    fmt.Println("END")


}

输出


go run app.go

10

11

12

4

7

1

2

3

5

6

8

9

fatal error: all goroutines are asleep - deadlock!


梵蒂冈之花
浏览 125回答 2
2回答

杨__羊羊

您正在使用for i := range c迭代通道,但代码不知道何时停止。range在通道上等待通道关闭,或永远挂起。这就是为什么会出现僵局。在通过频道发布所有“url”后,您应该关闭您的频道。这可以在 的帮助下实现sync.WaitGroup。在getNumbers循环之前,您可以使用 aWaitGroup并设置要等待的作业数len(urls):wg:=&sync.WaitGroup{}wg.Add(len(urls))并在返回之前添加一个新的协程ch:go func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(ch)} ()然后在 中allNumbersOfURL,添加WaitGroup作为新参数,并在循环后设置一个完成的工作。func allNumbersOfURL(url urlNumbers, ch chan int,wg *sync.WaitGroup) {&nbsp; &nbsp; for _, i := range url.numbers {&nbsp; &nbsp; &nbsp; &nbsp; ch <- i&nbsp; &nbsp; }&nbsp; &nbsp; wg.Done()}游乐场:https://play.golang.org/p/--7x7eXIzP9

江户川乱折腾

通道必须关闭,你可以用来sync.WaitGroup等待任务完成。这是对功能的修改getNumbersfunc getNumbers(urls []urlNumbers) <-chan int {&nbsp; &nbsp; ch := make(chan int)&nbsp; &nbsp; wg := &sync.WaitGroup{}&nbsp; &nbsp; for _, url := range urls {&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(url urlNumbers, ch chan<- int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; allNumbersOfURL(url, ch)&nbsp; &nbsp; &nbsp; &nbsp; }(url, ch)&nbsp; &nbsp; }&nbsp; &nbsp; go func(wg *sync.WaitGroup, ch chan int) {&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; close(ch)&nbsp; &nbsp; }(wg, ch)&nbsp; &nbsp; return ch}此外,我建议你在论证传递中使用通道方向。可选的 <- 运算符指定通道方向,发送或接收。如果没有给出方向,则通道是双向的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go