推迟多个Goroutines?

时间:2016-08-19 04:41:28

标签: go concurrency

我有以下代码:

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

1 个答案:

答案 0 :(得分:3)

您对错误导致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