Select on blocked call and channel

Viewed 69

I am pretty sure I've seen a question on this before but can't find it now.

Essentially I want to select on a blocked call as well as a channel.

I know I can push the blocked call into a goroutine and wait on the result via a channel, however that feels like the wrong solution.

Is there an idiomatic way to write this that I'm missing?

Optimally there would be something like:

select {
case a <- c:
  ...
case ans := connection.Read():
  ...
}
1 Answers

If you have a channel and a function of which you want to select, using a goroutine and a channel is the idiomatic solution. Note though that if a value is received from the channel, that will not affect the function and it will continue to run. You may use context.Context to signal its result is no longer needed and it may terminate early.

If you're allowed to refactor though, you can "make" the function send on the same channel, so you only need to receive from a single channel.

Another refactoring idea would be for the function to monitor the same channel and return early, so you may just do a single call without select.

Note that if you need to do this in many places, you may create a helper function to launch it asychronously:

func launch(f func()) <-chan struct{} {
    done := make(chan struct{})
    go func() {
        defer close(done)
        f()
    }()
    return done
}

Example function:

func test() {
    time.Sleep(time.Second)
}

And then using it:

select {
case a := <-c:
    fmt.Println("received from channel:", a)
case <-launch(test):
    fmt.Println("test() finished")

}

Try it on the Go Playground.

Related