I have a slice of integers, which are manipulated concurrently:
ints := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
I'm using a buffered channel as semaphore in order to have a an upper bound of concurrently running go routines:
sem := make(chan struct{}, 2)
for _, i := range ints {
// acquire semaphore
sem <- struct{}{}
// start long running go routine
go func(id int, sem chan struct{}) {
// do something
// release semaphore
<- sem
}(i, sem)
}
The code above works pretty well until the last or last two integers are reached, because the program ends before those last go routines are finished.
Question: how do I wait for the buffered channel to drain?
It is also possible to check the number of elements queued in a channel by using len(ch) , as stated in the Go specifications. This in combination with cap allows us to check if a channel is full without sending any data.
Buffered channel are blocked only when the buffer is full. Similarly receiving from a buffered channel are blocked only when the buffer will be empty. Buffered channels can be created by passing an additional capacity parameter to the make( ) function which specifies the size of the buffer.
You can't use a semaphore (channel in this case) in that manner. There's no guarantee it won't be empty any point while you are processing values and dispatching more goroutines. That's not a concern in this case specifically since you're dispatching work synchronously, but because there's no race-free way to check a channel's length, there's no primitive to wait for a channel's length to reach 0.
Use a sync.WaitGroup
to wait for all goroutines to complete
sem := make(chan struct{}, 2)
var wg sync.WaitGroup
for _, i := range ints {
wg.Add(1)
// acquire semaphore
sem <- struct{}{}
// start long running go routine
go func(id int) {
defer wg.Done()
// do something
// release semaphore
<-sem
}(i)
}
wg.Wait()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With