为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
梵蒂冈之花 2022-09-05 17:35:56
我正在阅读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然后我想...为什么他们当时没有这样编码呢?
查看完整描述

2 回答

?
桃花长相依

TA贡献1860条经验 获得超8个赞

另一个简单而相似的模式。


func hBeatTicker(ctx context.Context, ch chan<- struct{}, t time.Duration) {

    tick := time.NewTicker(t)

    for {

        select {

        case <-ctx.Done():

            close(ch)

            tick.Stop()

            return

        case <-tick.C:

            ch <- struct{}{}

        }

    }

}


func workGen(ctx context.Context, ch chan<- time.Time, t time.Duration) {

    tick := time.NewTicker(2 * t)

    for {

        select {

        case <-ctx.Done():

            close(ch)

            tick.Stop()

            return

        case ch <- <-tick.C:

        }

    }

}


func do(ctx context.Context, d time.Duration) (<-chan struct{}, <-chan time.Time) {

    heartbeat, results := make(chan struct{}), make(chan time.Time)


    go workGen(ctx, results, d)

    go hBeatTicker(ctx, heartbeat, d)


    return heartbeat, results

}


查看完整回答
反对 回复 2022-09-05
?
墨色风雨

TA贡献1853条经验 获得超6个赞

在选择中使用临时变量。根据当前状态将这些变量设置为或原始值。workgenresultsnil


将变量设置为 nil 将禁用选择的分支,因为 nil 通道上的通道操作会永久阻塞。


    workGenT := workGen

    var resultsT chan time.Time

    var result time.Time

    for {

        select {

        case <-done:

            return

        case <-pulse:

            sendPulse()

        case result = <-workgenT:

            workgenT = nil

            resultsT = results

        case resultsT <- result:

            resultsT = nil

            workgenT = workgen

        }

    }

因为只有一个 和 是非 nil,所以上面的代码有两种状态:程序正在等待接收结果或等待发送结果。workgenTresultsT


查看完整回答
反对 回复 2022-09-05
  • 2 回答
  • 0 关注
  • 84 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信