英文:
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 (
"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
}
答案2
得分: 5
在Go 1.15中引入了ticker.Reset
,这就是为什么你不需要创建一个新的ticker来更新现有ticker的持续时间,只需使用ticker.Reset("new duration")
来更新即可。现在你将不再遇到任何缓存问题。
你的示例代码中存在缓存问题的原因是,当你使用*time.ticker
结构重新分配ticker
变量时,只是将原始的*time.ticker
结构与ticker
变量解除了关联,但循环仍然与原始的ticker通道绑定,你需要为新的time.ticker.c
重新分配一个新的循环。
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("new duration")
, and now you will not have any cache issues
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()
}
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"捕获通道并使用相同的引用进行迭代。如果您像这样使用它,问题就会得到解决:
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 :
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()
}
答案4
得分: 0
这段代码是一个使用Go语言编写的程序。它创建了一个定时器,每隔一段时间加速一次,直到接收到停止信号。具体的代码逻辑如下:
- 导入了fmt、log和time包。
- 在main函数中,定义了一个startInterval变量,初始值为1000。
- 创建了一个名为quit的通道,用于发送停止信号。
- 使用匿名函数启动了一个goroutine。
- 在goroutine中,定义了一个counter变量,初始值为1.0。
- 使用select语句监听两个通道:time.After和quit。
- 当从time.After通道接收到值时,打印日志并将counter加1。
- 当从quit通道接收到值时,打印停止消息并返回。
- 在主goroutine中,使用time.Sleep函数暂停5秒。
- 打印停止消息。
- 向quit通道发送停止信号。
- 使用time.Sleep函数暂停500毫秒,以便查看停止消息。
该程序的功能是创建一个加速的定时器,并在一定时间后停止。
英文:
What about this code:
https://play.golang.org/p/wyOTVxUW5Xj
package main
import (
"fmt"
"log"
"time"
)
func main() {
startInterval := float64(1000)
quit := make(chan bool)
go func() {
counter := 1.0
for {
select {
case <-time.After(time.Duration(startInterval/counter) * time.Millisecond):
log.Println("ticker accelerating to " + fmt.Sprint(startInterval/counter) + " ms")
counter++
case <-quit:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论