我想做的是拥有一组生产者 goroutine(其中一些可能完成也可能不完成)和一个消费者例程。问题在于括号中的警告 - 我们不知道将返回答案的总数。
所以我想做的是:
package main
import (
"fmt"
"math/rand"
)
func producer(c chan int) {
// May or may not produce.
success := rand.Float32() > 0.5
if success {
c <- rand.Int()
}
}
func main() {
c := make(chan int, 10)
for i := 0; i < 10; i++ {
go producer(c, signal)
}
// If we include a close, then that's WRONG. Chan will be closed
// but a producer will try to write to it. Runtime error.
close(c)
// If we don't close, then that's WRONG. All goroutines will
// deadlock, since the range keyword will look for a close.
for num := range c {
fmt.Printf("Producer produced: %d\n", num)
}
fmt.Println("All done.")
}
所以问题是,如果我关闭它是错误的,如果我不关闭 - 它仍然是错误的(参见代码中的注释)。
现在,解决方案将是一个带外信号通道,所有生产者都写入:
package main
import (
"fmt"
"math/rand"
)
func producer(c chan int, signal chan bool) {
success := rand.Float32() > 0.5
if success {
c <- rand.Int()
}
signal <- true
}
func main() {
c := make(chan int, 10)
signal := make(chan bool, 10)
for i := 0; i < 10; i++ {
go producer(c, signal)
}
// This is basically a 'join'.
num_done := 0
for num_done < 10 {
<- signal
num_done++
}
close(c)
for num := range c {
fmt.Printf("Producer produced: %d\n", num)
}
fmt.Println("All done.")
}
这完全符合我的要求!但对我来说,这似乎是一口。我的问题是:是否有任何成语/技巧可以让我以更简单的方式做类似的事情?
我在这里看了一下:http: //golang.org/doc/codewalk/sharemem/
似乎complete
chan (在开头初始化main
)在一个范围内使用但从未关闭。我不明白怎么做。
如果有人有任何见解,我将不胜感激。干杯!
编辑:fls0815 有答案,并且还回答了无关闭通道范围如何工作的问题。
我上面的代码修改为工作(在 fls0815 提供代码之前完成):
package main
import (
"fmt"
"math/rand"
"sync"
)
var wg_prod sync.WaitGroup
var wg_cons sync.WaitGroup
func producer(c chan int) {
success := rand.Float32() > 0.5
if success {
c <- rand.Int()
}
wg_prod.Done()
}
func main() {
c := make(chan int, 10)
wg_prod.Add(10)
for i := 0; i < 10; i++ {
go producer(c)
}
wg_cons.Add(1)
go func() {
for num := range c {
fmt.Printf("Producer produced: %d\n", num)
}
wg_cons.Done()
} ()
wg_prod.Wait()
close(c)
wg_cons.Wait()
fmt.Println("All done.")
}