【问题标题】:deadlock when passing channel as argument in pipline在管道中将通道作为参数传递时出现死锁
【发布时间】:2019-02-26 11:05:51
【问题描述】:

我正在编写一种将数字分成 100 个组并同时计算阶乘的做法,但是我的代码给了我死锁。

我认为问题可能是管道链启动。由于所有函数都将通道作为参数,所以我不清楚为什么 main 中的 go func 没有将给定的 in 通道值传递给 genConcurrentGroup 函数当这条线 total:= <- c 发生时。

package main

import "fmt"

func main() {
    in := make (chan int)
    out := make (chan float64)

    go func() {
        in <- 1005
        out = calculateFacotorial(genConcurrentGroup(in))
    }()

    fmt.Println(<-in)
    fmt.Println(<-out)

}

//split input number into groups
//the result should be a map of [start number, number in group]
//this is not heavy task so run in one go routine
func genConcurrentGroup(c chan int) chan map[int]int{
    out := make(chan map[int]int)

    go func() {
        //100 groups
        total:= <- c  //DEADLOCK HERE! Why?
        //element number in group
        elemNumber := total / 100
        extra := total % 100
        result := make(map[int]int)
        if elemNumber>0{
            //certain 100 groups
            for i:=1 ;i<=99;i++{
                result[(i-1) * elemNumber + 1] = elemNumber
            }
            result[100] = extra + elemNumber
        }else{
            //less than 100
            for i:=1;i<=total;i++{
                result[i] = 1
            }
        }

        out <- result
        close(out)
    }()
    return out
}

//takes in all numbers to calculate multiply result
//this could be heavy so can do it 100 groups together
func calculateFacotorial(nums chan map[int]int) chan float64{
    out := make(chan float64)
    total:= <- nums //DEADLOCK HERE! Why?

    go func() {

        oneResult := make(chan float64)

        for k,v := range total{
            go func() {
                t := 1.0
                for i:=0;i<v;i++{
                    t *= float64(k) + float64(i)
                }
                oneResult <- t
            }()
        }
        result := 1.0
        for n := range oneResult{
            result *= n
        }

        close(oneResult)
    }()
    return out
}

【问题讨论】:

    标签: go


    【解决方案1】:

    1. total:= &lt;- c //DEADLOCK HERE! Why?

    您需要为您的in 频道添加一个缓冲区,因为您发送值时没有人接收。

    2。 total := &lt;-nums //DEADLOCK HERE! Why?

    您需要添加一个sync.WaitGroup 以等待所有 goroutine 结束,然后您可以关闭您的频道以循环它。

    没有死锁的完整代码:

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func main() {
        in := make(chan int, 1)
    
        in <- 1005
        out := calculateFacotorial(genConcurrentGroup(in))
    
        fmt.Println(<-out)
    
    }
    
    //split input number into groups
    //the result should be a map of [start number, number in group]
    //this is not heavy task so run in one go routine
    func genConcurrentGroup(c chan int) chan map[int]int {
        out := make(chan map[int]int)
    
        go func() {
            //100 groups
            total := <-c //DEADLOCK HERE! Why?
            //element number in group
            elemNumber := total / 100
            extra := total % 100
            result := make(map[int]int)
            if elemNumber > 0 {
                //certain 100 groups
                for i := 1; i <= 99; i++ {
                    result[(i-1)*elemNumber+1] = elemNumber
                }
                result[100] = extra + elemNumber
            } else {
                //less than 100
                for i := 1; i <= total; i++ {
                    result[i] = 1
                }
            }
    
            out <- result
            close(out)
        }()
        return out
    }
    
    //takes in all numbers to calculate multiply result
    //this could be heavy so can do it 100 groups together
    func calculateFacotorial(nums chan map[int]int) chan float64 {
        out := make(chan float64)
        total := <-nums //DEADLOCK HERE! Why?
    
        go func() {
            oneResult := make(chan float64, len(total))
    
            var wg sync.WaitGroup
            wg.Add(len(total))
    
            for k, v := range total {
                go func() {
                    t := 1.0
                    for i := 0; i < v; i++ {
                        t *= float64(k) + float64(i)
                    }
                    oneResult <- t
                    wg.Done()
                }()
            }
    
            wg.Wait()
    
            close(oneResult)
    
            result := 1.0
            for n := range oneResult {
                result *= n
            }
    
            out <- result
    
        }()
        return out
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 2017-10-05
    • 1970-01-01
    相关资源
    最近更新 更多