动态更改 ticker 的间隔。

huangapple go评论73阅读模式
英文:

dynamically change ticker interval

问题

我想动态改变我的ticker间隔。

我写了一个示例来展示我是如何做的。我的用例与“加速计”不同,但我希望它能给你一个想法。

package main

import (
    "time"
    "log"
    "fmt"
)

func main() {
    interval := float64(1000)

    ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)
    go func(){
        counter := 1.0
        for range ticker.C {
            log.Println("ticker accelerating to " + fmt.Sprint(interval/counter) + " ms")
            ticker = time.NewTicker(time.Duration(interval/counter) * time.Millisecond)
            counter++
        }
        log.Println("stopped")
    }()
    time.Sleep(5 * time.Second)
    log.Println("stopping ticker")
    ticker.Stop()
}

问题在于ticker总是每秒钟“tick”一次,而不会加速... 有什么想法吗?

英文:

I would like to change my ticker interval dynamically.

I've written down an example to show you how I did. My use case is something else than an "accelerometer" but I hope that it gives you an idea.

http://play.golang.org/p/6ANFnoE6pA

package main

import (
    "time"
    "log"
    "fmt"
)

func main() {
    interval := float64(1000)

    ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)
    go func(){
        counter := 1.0
        for range ticker.C {
            log.Println("ticker accelerating to " + fmt.Sprint(interval/counter) + " ms")
            ticker = time.NewTicker(time.Duration(interval/counter) * time.Millisecond)
            counter++
        }
        log.Println("stopped")
    }()
    time.Sleep(5 * time.Second)
    log.Println("stopping ticker")
    ticker.Stop()
}

What is wrong is that the ticker will always "tick" every seconds and it doesn't accelerate... Any idea?

答案1

得分: 8

根据@fzerorubigd的答案,但更完整一些。

如前所述,我们不能在这种情况下使用range,因为range循环会缓存要循环的变量,然后无法被覆盖(示例在这里:http://play.golang.org/p/yZvrgURz4o)。

因此,我们应该使用for-select组合循环。以下是可行的解决方案:

package main

import (
    "time"
    "log"
    "fmt"
)

func main() {
    start_interval := float64(1000)
    quit := make(chan bool)

    go func(){
        ticker := time.NewTicker(time.Duration(start_interval) * time.Millisecond)
        counter := 1.0

        for {
            select {
            case <-ticker.C:
                log.Println("ticker accelerating to " + fmt.Sprint(start_interval/counter) + " ms")
                ticker.Stop()
                ticker = time.NewTicker(time.Duration(start_interval/counter) * time.Millisecond)
                counter++
            case <-quit:
                ticker.Stop()
                log.Println("..ticker stopped!")
                return
            }
        }
    }()

    time.Sleep(5 * time.Second)

    log.Println("stopping ticker...")
    quit <- true

    time.Sleep(500 * time.Millisecond) // just to see quit messages
}

希望对你有帮助!

英文:

Following the answer to @fzerorubigd but a little more complete.

As said before, we can't use the range for this case, because the range loop caches the variable to be lopped and then it can't be overwritten (example here: http://play.golang.org/p/yZvrgURz4o )

Then, we should use a for-select combination loop. Hereafter the working solution:

http://play.golang.org/p/3uJrAIhnTQ

package main

import (
    &quot;time&quot;
    &quot;log&quot;
    &quot;fmt&quot;
)

func main() {
    start_interval := float64(1000)
    quit := make(chan bool)

    go func(){
	    ticker := time.NewTicker(time.Duration(start_interval) * time.Millisecond)
        counter := 1.0

        for {
	        select {
		    case &lt;-ticker.C:
	            log.Println(&quot;ticker accelerating to &quot; + fmt.Sprint(start_interval/counter) + &quot; ms&quot;)
	            ticker.Stop()
            	ticker = time.NewTicker(time.Duration(start_interval/counter) * time.Millisecond)
                counter++
 		    case &lt;-quit:
		        ticker.Stop()
		        log.Println(&quot;..ticker stopped!&quot;)
		        return
	        }
        }
    }()

    time.Sleep(5 * time.Second)

    log.Println(&quot;stopping ticker...&quot;)
    quit&lt;-true

    time.Sleep(500 * time.Millisecond) // just to see quit messages
}

答案2

得分: 5

在Go 1.15中引入了ticker.Reset,这就是为什么你不需要创建一个新的ticker来更新现有ticker的持续时间,只需使用ticker.Reset("new duration")来更新即可。现在你将不再遇到任何缓存问题。

你的示例代码中存在缓存问题的原因是,当你使用*time.ticker结构重新分配ticker变量时,只是将原始的*time.ticker结构与ticker变量解除了关联,但循环仍然与原始的ticker通道绑定,你需要为新的time.ticker.c重新分配一个新的循环。

Go playground

package main

import (
	"fmt"
	"log"
	"time"
)

func main() {
	interval := float64(1000)

	ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)
	go func(){
		counter := 1.0
		for range ticker.C {
			log.Println("ticker accelerating to " + fmt.Sprint(interval/counter) + " ms")
			ticker.Reset(time.Duration(interval/counter) * time.Millisecond)
			counter++
		}
		log.Println("stopped")
	}()
	time.Sleep(5 * time.Second)
	log.Println("stopping ticker")
	ticker.Stop()
}
英文:

that why in go1.15 ticker.Reset is Introduced, you don't need to create a new ticker update the existing ticker's duration with ticker.Reset(&quot;new duration&quot;), and now you will not have any cache issues

Go playground

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;time&quot;
)

func main() {
	interval := float64(1000)

	ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)
	go func(){
		counter := 1.0
		for range ticker.C {
			log.Println(&quot;ticker accelerating to &quot; + fmt.Sprint(interval/counter) + &quot; ms&quot;)
			ticker.Reset(time.Duration(interval/counter) * time.Millisecond)
			counter++
		}
		log.Println(&quot;stopped&quot;)
	}()
	time.Sleep(5 * time.Second)
	log.Println(&quot;stopping ticker&quot;)
	ticker.Stop()
}

The reason your example have a cache issue is that when you reassign the ticker variable with a *time.ticker struct you just unlink the original *time.ticker struct from the ticker variable but the loop is still tide to the original ticker channel you need to reassin a new loop to the new time.ticker.c

答案3

得分: 1

如Nipun Talukdar所提到的,"for"捕获通道并使用相同的引用进行迭代。如果您像这样使用它,问题就会得到解决:

playground

package main

import (
	"fmt"
	"log"
	"time"
)

func main() {
	interval := float64(1000)

	ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)
	go func() {
		counter := 1.0
		for {
			select {
			case <-ticker.C:
				log.Println("ticker accelerating to " + fmt.Sprint(interval/counter) + " ms")
				ticker = time.NewTicker(time.Duration(interval/counter) * time.Millisecond)
				counter++
			}
		}
		log.Println("stopped")
	}()
	time.Sleep(5 * time.Second)
	log.Println("stopping ticker")
	ticker.Stop()
}
英文:

As Nipun Talukdar mentioned, the "for" capture the channel and use the same reference for iterate. it fixed if you use it like this :

playground

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;time&quot;
)

func main() {
	interval := float64(1000)

	ticker := time.NewTicker(time.Duration(interval) * time.Millisecond)
	go func() {
		counter := 1.0
		for {
			select {
			case &lt;-ticker.C:
				log.Println(&quot;ticker accelerating to &quot; + fmt.Sprint(interval/counter) + &quot; ms&quot;)
				ticker = time.NewTicker(time.Duration(interval/counter) * time.Millisecond)
				counter++
			}
		}
		log.Println(&quot;stopped&quot;)
	}()
	time.Sleep(5 * time.Second)
	log.Println(&quot;stopping ticker&quot;)
	ticker.Stop()
}

答案4

得分: 0

这段代码是一个使用Go语言编写的程序。它创建了一个定时器,每隔一段时间加速一次,直到接收到停止信号。具体的代码逻辑如下:

  1. 导入了fmt、log和time包。
  2. 在main函数中,定义了一个startInterval变量,初始值为1000。
  3. 创建了一个名为quit的通道,用于发送停止信号。
  4. 使用匿名函数启动了一个goroutine。
  5. 在goroutine中,定义了一个counter变量,初始值为1.0。
  6. 使用select语句监听两个通道:time.After和quit。
  7. 当从time.After通道接收到值时,打印日志并将counter加1。
  8. 当从quit通道接收到值时,打印停止消息并返回。
  9. 在主goroutine中,使用time.Sleep函数暂停5秒。
  10. 打印停止消息。
  11. 向quit通道发送停止信号。
  12. 使用time.Sleep函数暂停500毫秒,以便查看停止消息。

该程序的功能是创建一个加速的定时器,并在一定时间后停止。

英文:

What about this code:

https://play.golang.org/p/wyOTVxUW5Xj

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;time&quot;
)

func main() {
	startInterval := float64(1000)
	quit := make(chan bool)

	go func() {
		counter := 1.0
		for {
			select {
			case &lt;-time.After(time.Duration(startInterval/counter) * time.Millisecond):
				log.Println(&quot;ticker accelerating to &quot; + fmt.Sprint(startInterval/counter) + &quot; ms&quot;)
				counter++
			case &lt;-quit:
				log.Println(&quot;..ticker stopped!&quot;)
				return
			}
		}
	}()

	time.Sleep(5 * time.Second)
	log.Println(&quot;stopping ticker...&quot;)
	quit &lt;- true
	time.Sleep(500 * time.Millisecond) // just to see quit messages
}

huangapple
  • 本文由 发表于 2016年4月18日 17:11:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/36689774.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定