编写此代码的更好的惯用方法?

Ale*_*lec 4 go

和go一起玩,我把这段代码拼凑在一起:

package main

import "fmt"

const N = 10

func main() {
    ch := make(chan int, N)
    done := make(chan bool)

    for i := 0; i < N; i++ {
        go (func(n int, ch chan int, done chan bool) {
            for i := 0; i < N; i++ {
                ch <- n*N + i
            }
            done <- true
        })(i, ch, done)
    }

    numDone := 0
    for numDone < N {
        select {
        case i := <-ch:
            fmt.Println(i)
        case <-done:
            numDone++
        }
    }

    for {
        select {
        case i := <-ch:
            fmt.Println(i)
        default:
            return
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上我有N个频道做一些工作并在同一频道上报道 - 我想知道所有频道何时完成.所以我有另一个done通道,每个工作者goroutine发送一条消息(消息无关紧要),这导致main将该线程计为完成.当计数到达N时,我们实际上已经完成了.

这是"好"吗?这样做有更多的惯用方法吗?

编辑:为了澄清一点,我很怀疑,因为done频道似乎正在做一个关闭频道的工作,但当然我无法在任何goroutine中关闭频道,因为所有例程共享相同的频道.所以我done用来模拟一个做某种"缓冲关闭"的频道.

edit2:原始代码并没有真正起作用,因为有时done来自例程的信号在它刚刚放入的int之前被读取ch.需要一个"清理"循环.

Nic*_*ood 10

以下是sync.WaitGroup的惯用法供您学习

(游乐场链接)

package main

import (
    "fmt"
    "sync"
)

const N = 10

func main() {
    ch := make(chan int, N)
    var wg sync.WaitGroup
    for i := 0; i < N; i++ {
        wg.Add(1)
        go func(n int) {
            defer wg.Done()
            for i := 0; i < N; i++ {
                ch <- n*N + i
            }
        }(i)
    }
    go func() {
        wg.Wait()
        close(ch)
    }()
    for i := range ch {
        fmt.Println(i)
    }
}
Run Code Online (Sandbox Code Playgroud)

注意在两个go例程定义中使用闭包,并注意第二个go语句等待所有例程完成,然后关闭通道,因此range可以使用.