So, as explained in this question, select statement chooses a channel operation at random. And I often see a pattern like this:
func foo(ctx context.Context, someChannel <-chan int) {
for {
select {
case someValue := <-someChannel:
//do some stuff until the context is done
expensiveComputation(someValue)
case <-ctx.Done():
//context is done - either canceled or time is up for timeout
return
}
}
}
but if we can not guarantee, witch case
in select
will fire, it is possible, that case <-ctx.Done()
will be selected not instantly, but after a couple of iterations of expensiveComputation(someValue)
, witch we actually don't need to do anymore, because context is canceled. It is also possible that it will never get selected, but that's too low of a probability...
Go spec also says that "A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received." So what's also possible is:
- sender closed a channel
someChannel
- sender canceled a context
now in the select statement there will be two operations, that can proceed, available, and one of them will be chosen at random, and again, some computation will potentially be done after context has been canceled.
So how to properly deal with it? Or, if I'm missing something here, what is it?