dongpao1873 2019-04-16 13:49
浏览 43
已采纳

了解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?

  • 写回答

1条回答 默认 最新

  • doutangshuan6473 2019-04-16 16:06
    关注

    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)
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题