go – Idiomatic way of handling a goroutine with one "return" value?-ThrowExceptions

Exception or error:

Imagine I want to write a function that returns a random number divided by 2:

func randomIntInHalf() int {
    return rand.Int() / 2
}

But then I decide I want to build this function for concurrency so I end up with:

func randomIntInHalf(c chan<- int) {
    c <- rand.Int() / 2
}

func main() {
    // Generate 10 random ints in parallel
    amount := 10
    c := make(chan int, amount)

    for i := 0; i < amount; i++ {
        go randomIntInHalf(c)
    }

    for i := 0; i < amount; i++ {
        fmt.Println(<-c)
    }

    close(c)
}

I see some issues with this approach. For example, I require the caller to close the channel when it’s done generating, making it possible that someone might call the function and leave the channel open indefinitely. It was sort of my understanding that you always want the sender to close the channel. A) is that true and b) is it even possible in this case? Is there a better way to write this code or approach this problem?

And, generally, is there a better, idiomatic approach for running a function in a parallel that only ever writes 1 (or a known N) value to the channel?

Thanks.

How to solve:

You do not need to close channels. Once it goes out of scope, it will be garbage collected. Closing a channel is usually used to send a done notification to the listener. So it is not even possible in your case.

Yours is an idiomatic approach for what you’re trying to achieve, but not the only one. Some others (not necessarily idiomatic) that I can think of are:

  • You can use a shared data structure and populate that from multiple goroutines with explicit synchronization,
  • You can keep a separate result for each goroutine, and pass in a pointer to it. Each goroutine sets its result without a need for synchronization, and when everything is done, the caller works with the results.

Leave a Reply

Your email address will not be published. Required fields are marked *