如何退出频道范围/收集结果

时间:2015-03-22 22:28:52

标签: concurrency go

我需要同时处理几个任务,然后收集"结果。下面是我提出的代码,但我想知道它是否是正确的方法(即惯用/最佳实践),或者如果有什么不对的话我可能会错过。

package main

import "fmt"
import "sync"

func main() {
    // ch is the int provider. Cap is 99 but it should 
    // really be 3
    ch := make(chan int, 99)
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            ch <- i
        }(i)
    }
    wg.Wait()
    for v := range ch {
        fmt.Println("consume ", v)
        if len(ch) == 0 {
            close(ch)
        }
    }
    fmt.Printf("All done")
}

2 个答案:

答案 0 :(得分:1)

没有什么错误与...它的工作原理。但是,关闭渠道(而不是消费者)确实应该是生产者的工作。

为此...我建议你将整个制作人流程移动到goroutine并等待..然后关闭频道:

package main

import "fmt"
import "sync"

func main() {
    ch := make(chan int, 3)
    var wg sync.WaitGroup

    go func() {
        for i := 0; i < 3; i++ {
            wg.Add(1)
            go func(i int) {
                defer wg.Done()
                ch <- i
            }(i)
        }
        wg.Wait()
        close(ch) // producer is now closing the channel
    }()

    // Consumer has the single responsibility of iterating over the channel
    for v := range ch {
        fmt.Println("consume ", v)
    }
    fmt.Printf("All done")
}

See it in the Go Playground

答案 1 :(得分:0)

我确信你的例子是人为的,但你的例子可以简单得多:

ch := make(chan int, 99)
for i := 0; i < 3; i++ {
    go func(i int) {
        ch <- i
    }(i)
}
for i := 0; i < 3; i++ {
    v := <- ch
    fmt.Println("consume ", v)
}
fmt.Println("All done")

您的真实代码可能更复杂,需要像waitGroup这样的东西,如果是这种情况,请尽你所能来解释您的具体问题。

关闭一个范围内的频道以退出该范围似乎是非惯用的Go。

Go Play