用于避免具有重复事例的嵌套选择的模式

我正在阅读O'Reilly的并发性在Go书中,发现了这个代码示例:


doWork := func(

    done <-chan interface{},

    pulseInterval time.Duration,

) (<-chan interface{}, <-chan time.Time) {

    heartbeat := make(chan interface{})

    results := make(chan time.Time)

    go func() {

        defer close(heartbeat)

        defer close(results)

        pulse := time.Tick(pulseInterval)

        workGen := time.Tick(2 * pulseInterval) // this just creates workload

        sendPulse := func() {

            select {

            case heartbeat <- struct{}{}:

            default:

            }

        }

        sendResult := func(r time.Time) {

            for {

                select {

                case <-done:

                    return

                case <-pulse:

                    sendPulse()

                case results <- r:

                    return

                }

            }

        }

        for {

            select {

            case <-done:

                return

            case <-pulse:

                sendPulse()

            case r := <-workGen:

                sendResult(r)

            }

        }

    }()

    return heartbeat, results

}

两个 select 语句用于简单的心跳似乎很奇怪。然后我明白了这背后的原因是 sendResult 不应该阻止尝试将结果发送到通道。如果没有人从该通道接收信号,它将有效地阻止 goroutine 并停止发送检测信号。results


然后我想...为什么他们当时没有这样编码呢?


梵蒂冈之花
浏览 85回答 2
2回答

桃花长相依

另一个简单而相似的模式。func hBeatTicker(ctx context.Context, ch chan<- struct{}, t time.Duration) {&nbsp; &nbsp; tick := time.NewTicker(t)&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close(ch)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tick.Stop()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; case <-tick.C:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch <- struct{}{}&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func workGen(ctx context.Context, ch chan<- time.Time, t time.Duration) {&nbsp; &nbsp; tick := time.NewTicker(2 * t)&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close(ch)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tick.Stop()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; case ch <- <-tick.C:&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func do(ctx context.Context, d time.Duration) (<-chan struct{}, <-chan time.Time) {&nbsp; &nbsp; heartbeat, results := make(chan struct{}), make(chan time.Time)&nbsp; &nbsp; go workGen(ctx, results, d)&nbsp; &nbsp; go hBeatTicker(ctx, heartbeat, d)&nbsp; &nbsp; return heartbeat, results}

墨色风雨

在选择中使用临时变量。根据当前状态将这些变量设置为或原始值。workgenresultsnil将变量设置为 nil 将禁用选择的分支,因为 nil 通道上的通道操作会永久阻塞。&nbsp; &nbsp; workGenT := workGen&nbsp; &nbsp; var resultsT chan time.Time&nbsp; &nbsp; var result time.Time&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case <-done:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; case <-pulse:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sendPulse()&nbsp; &nbsp; &nbsp; &nbsp; case result = <-workgenT:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; workgenT = nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resultsT = results&nbsp; &nbsp; &nbsp; &nbsp; case resultsT <- result:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resultsT = nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; workgenT = workgen&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }因为只有一个 和 是非 nil,所以上面的代码有两种状态:程序正在等待接收结果或等待发送结果。workgenTresultsT
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go