4

玩弄 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
        }
    }
}

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

这是“好”吗?有没有更惯用的方式来做到这一点?

编辑:澄清一下,我很怀疑,因为done频道似乎正在做频道关闭似乎是为了做的工作,但我当然不能在任何 goroutine 中真正关闭频道,因为所有例程都共享同一个频道. 所以我done用来模拟一个执行某种“缓冲关闭”的通道。

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

4

6 回答 6

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)
    }
}

注意两个goroutine定义中闭包的使用,注意第二条go语句等待所有的routine完成,然后关闭通道,所以range可以使用。

于 2013-04-15T18:43:10.533 回答
2

看起来你想要一个sync.WaitGrouphttp://golang.org/pkg/sync/#WaitGroup

于 2013-04-15T17:08:37.817 回答
1

只需使用 WaitGroup!它们是内置的原语,本质上让您等待不同 goroutine 中的内容完成。

http://golang.org/pkg/sync/#WaitGroup

至于您的疑问,解决方法是通过关闭通道(永久完成)和工作(暂时)完成是不同的。

于 2013-04-15T17:07:44.813 回答
1

在第一个近似值中,代码对我来说似乎或多或少没问题。

Wrt 的细节,'ch' 应该被缓冲。'done' 通道 goroutine “accounting” 也可能被 sync.WaitGroup 替换。

于 2013-04-15T17:15:30.403 回答
0

如果你正在迭代从 goroutines 生成的值,你可以直接迭代通信通道:

for value := range ch {
   println(value)
}

唯一需要的是,通道ch稍后关闭,否则循环将永远等待新值。

for numDone < Nsync.WaitGroup.

于 2013-04-15T18:43:20.523 回答
0

我在我的一些代码中处理了同样的问题,发现是一个绰绰有余的解决方案。

答案提供了 Go 的习惯用法,用于处理所有通过单个通道发送的多个 goroutine。

于 2013-04-16T23:11:48.250 回答