1

I need several goroutines to write in the same channel. Then all the data is read in one place until all the goroutines complete the process. But I'm not sure how best to close this channel.

this is my example implementation:

func main() {
    ch := make(chan data)
    wg := &sync.WaitGroup{}
    for instance := range dataSet {
        wg.Add(1)
        go doStuff(ch, instance)
    }
    go func() {
        wg.Wait()
        close(ch)
    }()

    for v := range ch { //range until it closes
        //proceed v
    }
}

func doStuff(ch chan data, instance data) {
    //do some stuff with instance...
    ch <- instance
}

but I'm not sure that it is idiomatic.

Peter
  • 29,454
  • 5
  • 48
  • 60
  • 3
    There is only one way to write to a channel, therefore there is only one way to write to a channel from multiple goroutines, and that is simply to write to the channel from multiple goroutines. So I don't really understand your question. – Jonathan Hall May 22 '19 at 08:52
  • 3
    What you did is perfectly fine. See possible duplicate: [Closing channel of unknown length](https://stackoverflow.com/questions/34283255/closing-channel-of-unknown-length/34283635#34283635). In general, the sender should close the channel. If there are multiple senders, you need coordination to only close the channel in one place, only once, and only when all senders are done with their job. – icza May 22 '19 at 08:58
  • 2
    One thing you forgot in your code: `doStuff()` should call `wg.Done()`, preferably deferred. – icza May 22 '19 at 09:10
  • Thank you! Yes my way is work fine (of course, there is `wg.Done()` is absent ). I only want to know is it the idiomatic? or there is more graceful way exists? – Владимир Савостин May 23 '19 at 11:51

1 Answers1

3

As you are using WaitGroup and increase the counter at the time of starting new goroutine, you have to notify WaitGroup when a goroutine is finished by calling the Done() method. Also you have to pass the same WaitGroup to the goroutine. You can do it by passing the address of WaitGroup. Otherwise each goroutine will use it's own WaitGroup which will be on different scope.

func main() {
    ch := make(chan data)
    wg := &sync.WaitGroup{}
    for _, instance := range dataSet {
        wg.Add(1)
        go doStuff(ch, instance, wg)
    }
    go func() {
        wg.Wait()
        close(ch)
    }()

    for v := range ch { //range until it closes
        //proceed v
    }
}

func doStuff(ch chan data, instance data, wg *sync.WaitGroup) {
    //do some stuff with instance...
    ch <- instance

    // call done method to decrease the counter of WaitGroup
    wg.Done()
}