Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat is the neatest idiom for producer/consumer in Go?
    primarykey
    data
    text
    <p>What I would like to do is have a set of producer goroutines (of which some may or may not complete) and a consumer routine. The issue is with that caveat in parentheses - we don't know the total number that will return an answer.</p> <p>So what I want to do is this:</p> <pre><code>package main import ( "fmt" "math/rand" ) func producer(c chan int) { // May or may not produce. success := rand.Float32() &gt; 0.5 if success { c &lt;- rand.Int() } } func main() { c := make(chan int, 10) for i := 0; i &lt; 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.") } </code></pre> <p>So the issue is, if I close it's wrong, if I don't close - it's still wrong (see comments in code).</p> <p>Now, the solution would be an out-of-band signal channel, that ALL producers write to:</p> <pre><code>package main import ( "fmt" "math/rand" ) func producer(c chan int, signal chan bool) { success := rand.Float32() &gt; 0.5 if success { c &lt;- rand.Int() } signal &lt;- true } func main() { c := make(chan int, 10) signal := make(chan bool, 10) for i := 0; i &lt; 10; i++ { go producer(c, signal) } // This is basically a 'join'. num_done := 0 for num_done &lt; 10 { &lt;- signal num_done++ } close(c) for num := range c { fmt.Printf("Producer produced: %d\n", num) } fmt.Println("All done.") } </code></pre> <p>And that totally does what I want! But to me it seems like a mouthful. My question is: Is there any idiom/trick that lets me do something similar in an easier way?</p> <p>I had a look here: <a href="http://golang.org/doc/codewalk/sharemem/">http://golang.org/doc/codewalk/sharemem/</a> And it seems like the <code>complete</code> chan (initialised at the start of <code>main</code>) is used in a range but never closed. I do not understand how.</p> <p>If anyone has any insights, I would greatly appreciate it. Cheers!</p> <hr> <p>Edit: fls0815 has the answer, and has also answered the question of how the close-less channel range works.</p> <p>My code above modifed to work (done before fls0815 kindly supplied code):</p> <pre><code>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() &gt; 0.5 if success { c &lt;- rand.Int() } wg_prod.Done() } func main() { c := make(chan int, 10) wg_prod.Add(10) for i := 0; i &lt; 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.") } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload