【问题标题】:Repeating countdown with different duration以不同的持续时间重复倒计时
【发布时间】:2016-01-28 15:46:57
【问题描述】:

我想制作一个具有 2 个不同持续时间的倒计时代码。做这个的最好方式是什么?我尝试这样做:

s5 := time.Tick(5 * time.Second)
m5 := time.Tick(5 * time.Minute)

for {
    select {
        case t := <-s5:
            ...
        case t := <-m5:
            ...
    }
}

但我需要不同时间间隔的代码:

5:00 -> 0:00
0:05 -> 0:00
5:00 -> 0:00
0:05 -> 0:00

这是惯用的方法吗?

【问题讨论】:

  • 你的版本有什么问题?
  • 它应该是一个持续时间为 5m-5s-5m-... 的股票,但我的版本每 5 分钟一次,我得到 60x5s 的滴答声和 1x5m 的滴答声

标签: go timer ticker


【解决方案1】:

如果你愿意,你可以调用 sleep

dur := 1 * time.Second
nextDur := 3 * time.Second

for {
    time.Sleep(dur)
    dur, nextDur = nextDur, dur

    ...
}

如果您需要select,或者在time.Timer 中交替使用持续时间。这是我个人会坚持的,因为您不必担心由于调度不一致而导致两个计时器之间的偏移。

dur := 1 * time.Second
nextDur := 3 * time.Second

timer := time.NewTimer(dur)

for {
    select {
    case t := <-timer.C:
        dur, nextDur = nextDur, dur
        timer.Reset(dur)
        ...
    }
    ...
}

或者运行 2 个按较小间隔偏移的计时器

dur1 := 1 * time.Second
dur2 := 3 * time.Second

timer1 := time.NewTimer(dur1)
timer2 := time.NewTimer(dur1 + dur2)

for {
    select {
    case t := <-timer1.C:
        timer1.Reset(dur1 + dur2)
        fmt.Println("timer1:", t)
    case t := <-timer2.C:
        timer2.Reset(dur1 + dur2)
        fmt.Println("timer2:", t)
    }

}

您也可以像最初尝试的那样运行交错的 Ticker,但这需要更多的协调来延迟其中一个的启动

dur1 := 1 * time.Second
dur2 := 3 * time.Second

ticker1 := time.NewTicker(dur1)
ticker2 := time.NewTicker(dur1 + dur2)

var once sync.Once
delayOnce := func() {
    ticker1.Stop()
    ticker1 = time.NewTicker(dur1 + dur2)
}

for  {
    select {
    case t := <-ticker1.C:
        once.Do(delayOnce)
        fmt.Println("ticker1:", t)
    case t := <-ticker2.C:
        fmt.Println("ticker2:", t)
    }

}

【讨论】:

    【解决方案2】:

    一种解决方案是只有 1 个每 5 秒滴答一次的代码。 5 分钟加 5 秒是 61*5 秒。所以“周期”是 61 个刻度。每个61th 刻度是5 分钟标记,每个61th+1 刻度是5 秒标记。由于只有一个代码,因此甚至不需要select

    c, count := time.Tick(5*time.Second), 1
    for {
        <-c
        count++
        switch count % 61 {
        case 0:
            fmt.Println("5-min mark")
        case 1:
            fmt.Println("5-sec mark")
        }
    }
    

    注意:由于count是用1初始化的,所以第一个“任务”将是5-min mark,在启动后5分钟后执行。

    另一种解决方案是使用 2 个time.Sleep() 调用序列,第一个是 5 分钟,第二个是 5 秒:

    for {
        time.Sleep(5 * time.Minute)
        fmt.Println("5-min mark")
        time.Sleep(5 * time.Second)
        fmt.Println("5-sec mark")
    }
    

    但是这个时间也取决于你执行的任务。所以要么使用第一个解决方案,要么在单独的 goroutines 中执行任务,这样它们就不会干扰时间,例如:

    for {
        time.Sleep(5 * time.Minute)
        go func () {
            fmt.Println("5-min mark")
        }
        time.Sleep(5 * time.Second)
        go func () {
            fmt.Println("5-sec mark")
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多