In Go, channels and wait groups (sync.WaitGroup
) are both concurrency primitives that help manage synchronization and coordination between goroutines. However, they serve different purposes and are used in different scenarios.
Channels:
Channels are used for communication and synchronization between goroutines. They allow data to be safely sent between goroutines and provide a way to coordinate their execution. Key points about channels include:
Send and Receive:
ch <- data
: Sends data to the channel.data := <-ch
: Receives data from the channel.
Blocking:
- Sending to a channel blocks until there is a goroutine ready to receive.
- Receiving from a channel blocks until there is data available.
Buffered and Unbuffered:
- Channels can be buffered (with a specified capacity) or unbuffered.
- Unbuffered channels have no capacity, and sending blocks until the data is received.
Close:
- Channels can be closed to signal that no more data will be sent.
- Closing a channel is a signal to receivers that no more values will be sent.
Example:
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
ch <- 42
close(ch)
}()
value, ok := <-ch
fmt.Println(value, ok) // 42 true
value, ok = <-ch
fmt.Println(value, ok) // 0 false (default zero value for int)
}
Wait Group (sync.WaitGroup
):
Wait groups are used to wait for a collection of goroutines to finish their execution before proceeding. They provide a way to wait for a specific number of goroutines to complete. Key points about wait groups include:
Add, Done, and Wait:
wg.Add(n)
: Addsn
to the wait group counter.wg.Done()
: Decrements the counter.wg.Wait()
: Blocks until the counter becomes zero.
Synchronization:
- Wait groups provide a mechanism to synchronize the execution of multiple goroutines.
Wait for Completion:
- Use
wg.Wait()
to block the execution of the main goroutine until all spawned goroutines have finished.
- Use
Example:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println("Goroutine", i)
}(i)
}
wg.Wait()
fmt.Println("All goroutines finished.")
}
When to Use Each:
Use channels when you need to communicate and synchronize between goroutines, especially when passing data between them.
Use wait groups when you need to wait for a specific number of goroutines to finish before proceeding, without necessarily passing data between them.
In many cases, you may find yourself using both channels and wait groups in a concurrent program, each serving its specific purpose.