Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the Advantage of sync.WaitGroup over Channels?

I'm working on a concurrent Go library, and I stumbled upon two distinct patterns of synchronization between goroutines whose results are similar:

Waitgroup

package main  import (     "fmt"     "sync"     "time" )  var wg sync.WaitGroup  func main() {     words := []string{"foo", "bar", "baz"}      for _, word := range words {         wg.Add(1)         go func(word string) {             time.Sleep(1 * time.Second)             defer wg.Done()             fmt.Println(word)         }(word)     }     // do concurrent things here      // blocks/waits for waitgroup     wg.Wait() } 

Channel

package main  import (     "fmt"     "time" )  func main() {     words := []string{"foo", "bar", "baz"}     done := make(chan bool)     // defer close(done)     for _, word := range words {         // fmt.Println(len(done), cap(done))         go func(word string) {             time.Sleep(1 * time.Second)             fmt.Println(word)             done <- true         }(word)     }     // Do concurrent things here      // This blocks and waits for signal from channel     for range words {         <-done     } }  

I was advised that sync.WaitGroup is slightly more performant, and I have seen it being used commonly. However, I find channels more idiomatic. What is the real advantage of using sync.WaitGroup over channels and/or what might be the situation when it is better?

like image 263
Pandemonium Avatar asked Mar 17 '16 09:03

Pandemonium


People also ask

When to use WaitGroup in golang?

A common usage of WaitGroup is to block the main function because we know that the main function itself is also a GoRoutine. You need to import the sync package before you can use WaitGroup.

What is WaitGroup add?

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.

What is the difference between a buffered channel and an unbuffered channel?

When a channel is created with no capacity, it is called an unbuffered channel. In turn, a channel created with capacity is called a buffered channel.

How do I close a channel in Golang?

We can close a channel in Golang with the help of the close() function. Once a channel is closed, we can't send data to it, though we can still read data from it. A closed channel denotes a case where we want to show that the work has been done on this channel, and there's no need for it to be open.


1 Answers

Independently of the correctness of your second example (as explained in the comments, you aren't doing what you think, but it's easily fixable), I tend to think that the first example is easier to grasp.

Now, I wouldn't even say that channels are more idiomatic. Channels being a signature feature of the Go language shouldn't mean that it is idiomatic to use them whenever possible. What is idiomatic in Go is to use the simplest and easiest to understand solution: here, the WaitGroup convey both the meaning (your main function is Waiting for workers to be done) and the mechanic (the workers notify when they are Done).

Unless you're in a very specific case, I don't recommend using the channel solution here.

like image 200
Elwinar Avatar answered Sep 22 '22 15:09

Elwinar