了解Go中的正常频道关闭

In this article from Go101 site I have read some trick with double selection for stopCh channel (in section "2. One receiver, N senders, the only receiver says "please stop sending more" by closing an additional signal channel").

Could you please describe how it works and do I really need to use it in real-world applications?

UPD: I don't asked about channel close. I have asked about usage of this part of the code:

        // The try-receive operation is to try
        // to exit the goroutine as early as
        // possible. For this specified example,
        // it is not essential.
        select {
        case <- stopCh:
            return
        default:
        }

        // Even if stopCh is closed, the first
        // branch in the second select may be
        // still not selected for some loops if
        // the send to dataCh is also unblocked.
        // But this is acceptable for this
        // example, so the first select block
        // above can be omitted.
        select {
        case <- stopCh:
            return
        case dataCh <- rand.Intn(Max):
        }

What is the real use case for double selection of stopCh?

The key here is to understand how select behaves if multiple cases can proceed, namely pseudo-randomly:

  1. If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection.

https://golang.org/ref/spec#Select_statements

select {
case <- stopCh:
    return
case dataCh <- rand.Intn(Max):
}

With only this second select statement, after stopCh has been closed, it is possible that both cases can proceed if at least one of the following is true:

  1. dataCh is buffered and is not at capacity
  2. at least one goroutine attempts to receive from dataCh even after stopCh has been closed

Without checking stopCh explicitely it is possible (albeit unlikely), that the runtime repeatedly chooses the second case even though the goroutine is expected to exit. If the goroutine happens to launch a missile in every iteration you can see how this may be a problem.

If both of these condition can be positively ruled out, the first select statement can be omitted because it is impossible that both cases are ready to proceed. The Go101 article simply shows a solution that is guaranteed to work, without making any assumptions.

This pattern is not uncommon in real-world code, and typically related to context cancellation:

func f(ctx context.Context, ch chan T) {
    for {
        // Make sure we don't shoot after ctx has been
        // canceled, even if a target is already lined up.
        select {
        case <-ctx.Done():
            return
        default:
        }

        // Or, equivalently: if ctx.Err() != nil { return }


        select {
        case <-ctx.Done():
            return
        case t := <-ch:
            launchMissileAt(t)
        }
    }
}