【问题标题】:Defer close on multiple Goroutines?推迟关闭多个 Goroutines?
【发布时间】:2016-08-19 04:41:27
【问题描述】:

我有以下代码:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Now()
    stuff := fanIn(
        generator(4, 5, 6, 7),
        generator(1, 2, 6, 3, 7),
        generator(12, 15, 33, 40, 10),
        generator(18, 13, 20, 40, 15),
        generator(100, 200, 64000, 3121, 1237),
    )

    for v := range stuff {
        fmt.Println(v)
    }

    fmt.Println(t.Sub(time.Now()))
}

func generator(nums ...int) <-chan int {
    out := make(chan int, 10)
    go func() {
        defer close(out)
        for _, v := range nums {
            out <- v
        }
    }()
    return out
}

func fanIn(in ...<-chan int) <-chan int {
    out := make(chan int, 10)

    for _, v := range in {
        go func(ch <-chan int) {
            for val := range ch {
                go func(c int) { out <- c }(val)
            }
        }(v)
    }

    return out
}

导致第 18 行出现死锁:

for v := range stuff {...}

问题(我认为)是我没有推迟关闭返回只读通道的 fanIn 函数。我不知道什么时候推迟它,因为它必须等待多个 goroutine 结束才能完成。

解决这个僵局的惯用方法是什么?这段代码甚至是惯用的吗?

谢谢!

GoPlay

【问题讨论】:

    标签: go concurrency


    【解决方案1】:

    您对未关闭fanIn 的频道的错误原因是正确的。您可以使用sync.WaitGroup 解决问题:

    func fanIn(in ...<-chan int) <-chan int {
        // use a WaitGroup here
        var wg sync.WaitGroup
        out := make(chan int, 10)
    
        for _, v := range in {
            wg.Add(1)
            go func(ch <-chan int) {
                defer wg.Done()
                for val := range ch {
                    out <- val
                }
            }(v)
        }
    
        // wait for wait groups to finish in another goroutine
        go func() {
            wg.Wait()
            close(out)
        }()
        return out
    }
    

    Working code.

    【讨论】:

    • 太棒了。我想我需要一个 sync.WG,但我没想到在另一个 goroutine 中使用它。有时很容易。谢谢!
    • 只是为了清楚起见:没有办法只使用 chan 原语吗?我们完全需要一个 WaitGroup 来关闭 fanIn(或合并)func 的 out-chan?
    • 如果您事先知道操作的数量,例如,从固定数量的 goroutines 到达通道的消息数量,那么最好只使用通道进行同步。例如,只是for 在频道上循环(不是range)一定次数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 2018-04-02
    • 2019-05-13
    • 2019-01-13
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多