为了账号安全,请及时绑定邮箱和手机立即绑定

多个 goroutines 和一个通道的死锁

多个 goroutines 和一个通道的死锁

Go
梵蒂冈之花 2023-05-22 17:23:49
我有一个我无法解决的死锁问题。我拥有一些 url,goroutine 中的每个 url 都会给我带来足够的数据。我将这些数据放入单个通道中。但是,如果我关闭频道,程序将无法运行,如果我离开频道,则会出现打开死锁。不知道怎么解决,求大神解答下面我把问题简化一下package mainimport (    "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.go101112471235689fatal error: all goroutines are asleep - deadlock!
查看完整描述

2 回答

?
杨__羊羊

TA贡献1943条经验 获得超7个赞

您正在使用for i := range c迭代通道,但代码不知道何时停止。range在通道上等待通道关闭,或永远挂起。这就是为什么会出现僵局。


在通过频道发布所有“url”后,您应该关闭您的频道。这可以在 的帮助下实现sync.WaitGroup。在getNumbers循环之前,您可以使用 aWaitGroup并设置要等待的作业数len(urls):


wg:=&sync.WaitGroup{}

wg.Add(len(urls))

并在返回之前添加一个新的协程ch:


go func() {

    wg.Wait()

    close(ch)

} ()

然后在 中allNumbersOfURL,添加WaitGroup作为新参数,并在循环后设置一个完成的工作。


func allNumbersOfURL(url urlNumbers, ch chan int,wg *sync.WaitGroup) {

    for _, i := range url.numbers {

        ch <- i

    }

    wg.Done()

}

游乐场:https://play.golang.org/p/--7x7eXIzP9


查看完整回答
反对 回复 2023-05-22
?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

通道必须关闭,你可以用来sync.WaitGroup等待任务完成。这是对功能的修改getNumbers


func getNumbers(urls []urlNumbers) <-chan int {

    ch := make(chan int)


    wg := &sync.WaitGroup{}

    for _, url := range urls {

        wg.Add(1)

        go func(url urlNumbers, ch chan<- int) {

            defer wg.Done()

            allNumbersOfURL(url, ch)

        }(url, ch)

    }


    go func(wg *sync.WaitGroup, ch chan int) {

        wg.Wait()

        close(ch)

    }(wg, ch)


    return ch

}

此外,我建议你在论证传递中使用通道方向。


可选的 <- 运算符指定通道方向,发送或接收。如果没有给出方向,则通道是双向的。


查看完整回答
反对 回复 2023-05-22
  • 2 回答
  • 0 关注
  • 124 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信