私がやりたいのは、一連のプロデューサーゴルーチン(一部は完了している場合と完了していない場合があります)とコンシューマールーチンを用意することです。問題は括弧内の警告にあります-答えを返す総数はわかりません。
だから私がしたいのはこれです:
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.")
}