【问题标题】:Go program does not deadlock but also never returnsGo 程序不会死锁但也永远不会返回
【发布时间】:2018-03-29 23:27:15
【问题描述】:

附加的要点是一个在生产者/多消费者模型中使用通道的简单程序。不知为何,

go run channels.go 打印所有结果但不返回(并且不会死锁,或者至少 go 不会让我担心发生死锁。)

type walkietalkie struct {
    in chan int
    out chan int
    quit chan bool
}

var items []int = []int{
    0, 1, 2, 3, 4, 5,
}

func work1(q walkietalkie) {
    for {
        select {
        case a, more := <- q.in:
            if more {
                q.out <- a * 2
            }
        default:
            break
        }
    }
}

func work2(q walkietalkie) {
    for  {
        select {
        case a, more := <- q.in:
            if more {
                q.out <- a * -1
            }
        default:
            break
        }
    }
}

func work3(q walkietalkie) {
    for  {
        select {
        case a, more := <- q.in:
            if more {
                q.out <- a * 7
            }
            default:
                break
        }
    }
}

func main() {
    results := make(chan int, 18)
    defer close(results)

    w := []walkietalkie{
        walkietalkie{ in: make(chan int, 6), out: results, quit: make(chan bool, 1) },
        walkietalkie{ in: make(chan int, 6), out: results, quit: make(chan bool, 1) },
        walkietalkie{ in: make(chan int, 6), out: results, quit: make(chan bool, 1) },
    }

    go work1(w[0])
    go work2(w[1])
    go work3(w[2])

    // Iterate over work items
    l := len(items)
    for i, e := range items {
        // Send the work item to each worker
        for _, f := range w {
            f.in <- e // send the work item
            if i == l - 1 { // This is the last input, close the channel
                close(f.in)
            }
        }
    }

    // Read all the results from the workers
    for {
        select {
        case r, more := <-results:
            if more {
                fmt.Println(r)
            } else {
                continue
            }
        default:
            break
        }
    }

}

【问题讨论】:

  • 在这里发布代码。接收到所有值后,main 函数在一个紧密的循环中旋转。
  • select 语句没有意义。看来您正在寻找for/range loops
  • main 一直运行到results 关闭,但results 直到main 返回才关闭。因此main 中的最后一个for 循环将永远运行。而且即使正确关闭,default: break 也只会从select 中跳出,而不是在for 之外,所以它仍然会永远运行。

标签: go channels


【解决方案1】:

你有几个问题。

对于 1,从具有多个返回值的通道读取,例如

case a, more := <-q.in 

将在关闭的频道上进行,更多设置为 false。在您的情况下,default 永远不会被击中。

但是这些都在 goroutines 中并且不会阻止程序退出。问题是您的主要 goroutine 正在做同样的事情。此外,事实证明,break 将跳出选择以及 for 循环。所以如果你想打破 for 循环,那么你需要使用标签和break LABEL

作为替代方案,您也可以直接返回而不是中断您的主 goroutine。

【讨论】:

  • 除了results 直到main 返回才关闭,使其成为书面的catch-22(即使它被写入以在通道关闭时正确退出循环)。
猜你喜欢
  • 1970-01-01
  • 2019-11-15
  • 2011-07-25
  • 1970-01-01
  • 2012-10-02
  • 2013-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多