Better go-idiomatic way to write this code?

Playing with go, I compiled this code:

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

Basically, I have N channels that do some work and report it on one channel - I want to know when all the channels will be completed. Therefore, I have this other done channel, which every working goroutine sends a message (the message does not matter), and this forces main to consider this thread as executed. When the counter reaches N, we are actually done.

Is it "good"? Is there a more idiomatic way to do this?

edit: To clarify a bit, I doubt because the done channel seems to be doing the job for which it seems like closing the channel, but of course I can't actually close the channel in any goroutine, because all the routines use the same channel. Therefore, I use done to simulate a channel that does some kind of "buffered close".

edit2: The source code did not work, because sometimes the done signal from the procedure was read before int just put on ch . A โ€œclean upโ€ cycle is required.

+4
source share
6 answers

Here is the idiomatic use of sync.WaitGroup for learning

( link to playgrounds )

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

Pay attention to the use of gates in the definitions of the definition of two go and pay attention to the second go statement to wait for the completion of all procedures, then close the channel, so range can be used.

+10
source

it looks like you want sync.WaitGroup ( http://golang.org/pkg/sync/#WaitGroup )

+2
source

Just use WaitGroup! This is a built-in primitive, which essentially allows you to wait until the material in different larynx is over.

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

As for your doubts, what is happening is that the execution of a closed channel (performed continuously) and the execution of work (temporarily) are different.

+1
source

In a first approximation, the code seems to me more or less suitable.

Enter the details, "ch" should be buffered. Also, the "ready" channel "accounting" can be replaced by sync.WaitGroup.

+1
source

If you repeat the values โ€‹โ€‹generated from goroutines, you can iterate directly over the communication channel:

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

The only thing necessary for this is that the ch channel will be closed later, otherwise the loop will wait for new values โ€‹โ€‹forever.

This will effectively replace your for numDone < N when used in conjunction with sync.WaitGroup .

0
source

I was dealing with the same problem in some of my code and found this to be more than an adequate solution.

In response, a Go idiot is provided to handle multiple goroutines sending over the same channel.

0
source

All Articles