英文:
How to stop a periodic function in golang
问题
所以我有一个函数,每隔2秒钟调用一次。像这样:
package main
import (
"fmt"
"time"
)
func doEvery(d time.Duration, f func(time.Time)) {
for x := range time.Tick(d) {
f(x)
}
}
func helloworld(t time.Time) {
fmt.Printf("%v: Hello, World!\n", t)
}
func main() {
doEvery(20*time.Millisecond, helloworld)
}
现在假设我不再希望这个函数每隔2秒钟执行一次。在golang中有没有办法实现这一点?或者在golang中调用定期函数是否有更好的方法?谢谢。
英文:
So I have a function that is called after every 2 seconds. Like this
package main
import (
"fmt"
"time"
)
func doEvery(d time.Duration, f func(time.Time)) {
for x := range time.Tick(d) {
f(x)
}
}
func helloworld(t time.Time) {
fmt.Printf("%v: Hello, World!\n", t)
}
func main() {
doEvery(20*time.Millisecond, helloworld)
}
Now lets say I no longer want this function to execute after every 2 seconds. Is there a way I can achieve this in golang? Or is there any better way than this to call a periodic function in golang? Thank you.
答案1
得分: 4
time.Tick()
的文档说明表示它无法停止:
> Tick是NewTicker的便利包装,仅提供对滴答通道的访问。虽然Tick对于不需要关闭Ticker的客户端很有用,但请注意,如果没有关闭它的方法,底层的Ticker将无法被垃圾回收器回收;它会“泄漏”。
如果你需要停止它,请改用time.NewTicker()
。在一个新的goroutine中运行doEvery()
,并传递一个通道给它,通过关闭通道来停止它,例如:
func doEvery(d time.Duration, done chan bool, f func(time.Time)) {
ticker := time.NewTicker(d)
defer ticker.Stop()
for {
select {
case <-done:
fmt.Println("Done!")
return
case t := <-ticker.C:
f(t)
}
}
}
进行测试:
done := make(chan bool)
go doEvery(300*time.Millisecond, done, helloworld)
time.Sleep(time.Second)
close(done)
time.Sleep(time.Second)
fmt.Println("Quitting")
这将输出(在Go Playground上尝试):
2009-11-10 23:00:00.3 +0000 UTC m=+0.300000001: Hello, World!
2009-11-10 23:00:00.6 +0000 UTC m=+0.600000001: Hello, World!
2009-11-10 23:00:00.9 +0000 UTC m=+0.900000001: Hello, World!
Done!
Quitting
英文:
Documentation of time.Tick()
states it cannot be stopped:
> Tick is a convenience wrapper for NewTicker providing access to the ticking channel only. While Tick is useful for clients that have no need to shut down the Ticker, be aware that without a way to shut it down the underlying Ticker cannot be recovered by the garbage collector; it "leaks".
If you need to stop it, use time.NewTicker()
instead. Run doEvery()
in a new goroutine, and pass a channel to it which gives you a mean to stop it, e.g. by closing the channel:
func doEvery(d time.Duration, done chan bool, f func(time.Time)) {
ticker := time.NewTicker(d)
defer ticker.Stop()
for {
select {
case <-done:
fmt.Println("Done!")
return
case t := <-ticker.C:
f(t)
}
}
}
Testing it:
done := make(chan bool)
go doEvery(300*time.Millisecond, done, helloworld)
time.Sleep(time.Second)
close(done)
time.Sleep(time.Second)
fmt.Println("Quitting")
This will output (try it on the Go Playground):
2009-11-10 23:00:00.3 +0000 UTC m=+0.300000001: Hello, World!
2009-11-10 23:00:00.6 +0000 UTC m=+0.600000001: Hello, World!
2009-11-10 23:00:00.9 +0000 UTC m=+0.900000001: Hello, World!
Done!
Quitting
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论