ctx.Err() vs ctx.Done() chan closed check: Is there a difference?

Viewed 1938

I am in a long running cancellable function that has a forever-loop.

I need to check if context is closed.

go func(){
    for {
         if ctx.Err() != nil { return }
         // do work
    }
}()

vs

go func(){
    for {
         select {
            case <-ctx.Done():
                return
            default:
         }
         // do work
    }
}()

Is there a difference between the two?

I am guessing checking ctx.Err() is safe for concurrent-access https://golang.org/src/context/context.go#L370 so they seem identical, given a closed context will always have Err set.

1 Answers

From the context.Context documentation:

If Done is not yet closed, Err returns nil. If Done is closed, Err returns a non-nil error explaining why

By extension, we can say that your first sample is checking if Done is closed. Given the convention for done channels that they should only ever be closed, and never have any values sent on them, we can say that your second sample is also checking if Done is closed.

So, we can say that the two code samples are functionally equivalent. The reason why we have different ways to check is because each offers some benefit:

  • Err() is an immediate check and gives error information.
  • Done() is a channel, and so can waited on or used in a select case.
Related