Search code examples
gochannelgoroutine

Stuck with Channels in golang


I need to run a function multiple times in parallel.
If even once the functions returns true (sends true on the channel) then the final result should be true.

How do I achieve this using goroutines and channels?

// Some performance intensive function
func foo(i int, c chan bool) {
    // do some processing and return either true or false
    c <- true // or false
}

func main() {
    flg := false
    ch := make(chan bool)
    for i := 0; i < 10; i++ {
        go foo(i, ch)
    }
    // If even once foo() returned true then val should be true
    flg = flg || <-ch
}

Solution

  • You only receive one value from the channel (which will be the value sent by one of the foo() calls, unpredictable which of the many), but you want to receive all.

    So use a for loop to receive as many values as you send (sent) on it:

    for i := 0; i < 10; i++ {
        flg = flg || <-ch
    }
    

    Although in your case it would be enough to loop until one true value is received, as that will determine the final value of flg, but it is still recommended to receive all values else the remaining goroutines will be blocked (as ch is an unbuffered channel). In this example it does not matter, but in a "real-life" application it would cause goroutines to stuck forever (memory-leak).

    If you don't want to wait for all foo() calls to complete and return as soon as possible (as soon as one true value is encountered), an option is to make ch buffered, so all goroutines can send values on it without getting blocked. And this way you are not required to receive (and thus wait for) all the foo() calls to complete:

    ch := make(chan bool, 10)
    for i := 0; i < 10; i++ {
        go foo(i, ch)
    }
    
    flg := false
    for i := 0; i < 10; i++ {
        if <-ch {
            flg = true
            break
        }
    }
    

    Choosing this approach, you should provide means to cancel goroutines whose work is no longer needed to avoid unnecessary CPU (and memory) usage. context.Context is such a mean, read more about it here: Close multiple goroutine if an error occurs in one in go.