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

报告相同问题?

悬赏问题

  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)
  • ¥15 相敏解调 matlab
  • ¥15 求lingo代码和思路
  • ¥15 公交车和无人机协同运输
  • ¥15 stm32代码移植没反应
  • ¥15 matlab基于pde算法图像修复,为什么只能对示例图像有效
  • ¥100 连续两帧图像高速减法