Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait until buffered channel (semaphore) is empty?

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?

like image 591
Kiril Avatar asked Sep 29 '16 17:09

Kiril


People also ask

How do I know if a buffered channel is full?

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.

What happens when a buffered channel is full?

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.


1 Answers

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()
like image 106
JimB Avatar answered Oct 19 '22 12:10

JimB