如何在Golang中停止一个周期性函数

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

How to stop a periodic function in golang

问题

所以我有一个函数,每隔2秒钟调用一次。像这样:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func doEvery(d time.Duration, f func(time.Time)) {
  7. for x := range time.Tick(d) {
  8. f(x)
  9. }
  10. }
  11. func helloworld(t time.Time) {
  12. fmt.Printf("%v: Hello, World!\n", t)
  13. }
  14. func main() {
  15. doEvery(20*time.Millisecond, helloworld)
  16. }

现在假设我不再希望这个函数每隔2秒钟执行一次。在golang中有没有办法实现这一点?或者在golang中调用定期函数是否有更好的方法?谢谢。

英文:

So I have a function that is called after every 2 seconds. Like this

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func doEvery(d time.Duration, f func(time.Time)) {
  7. for x := range time.Tick(d) {
  8. f(x)
  9. }
  10. }
  11. func helloworld(t time.Time) {
  12. fmt.Printf("%v: Hello, World!\n", t)
  13. }
  14. func main() {
  15. doEvery(20*time.Millisecond, helloworld)
  16. }

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(),并传递一个通道给它,通过关闭通道来停止它,例如:

  1. func doEvery(d time.Duration, done chan bool, f func(time.Time)) {
  2. ticker := time.NewTicker(d)
  3. defer ticker.Stop()
  4. for {
  5. select {
  6. case <-done:
  7. fmt.Println("Done!")
  8. return
  9. case t := <-ticker.C:
  10. f(t)
  11. }
  12. }
  13. }

进行测试:

  1. done := make(chan bool)
  2. go doEvery(300*time.Millisecond, done, helloworld)
  3. time.Sleep(time.Second)
  4. close(done)
  5. time.Sleep(time.Second)
  6. fmt.Println("Quitting")

这将输出(在Go Playground上尝试):

  1. 2009-11-10 23:00:00.3 +0000 UTC m=+0.300000001: Hello, World!
  2. 2009-11-10 23:00:00.6 +0000 UTC m=+0.600000001: Hello, World!
  3. 2009-11-10 23:00:00.9 +0000 UTC m=+0.900000001: Hello, World!
  4. Done!
  5. 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:

  1. func doEvery(d time.Duration, done chan bool, f func(time.Time)) {
  2. ticker := time.NewTicker(d)
  3. defer ticker.Stop()
  4. for {
  5. select {
  6. case &lt;-done:
  7. fmt.Println(&quot;Done!&quot;)
  8. return
  9. case t := &lt;-ticker.C:
  10. f(t)
  11. }
  12. }
  13. }

Testing it:

  1. done := make(chan bool)
  2. go doEvery(300*time.Millisecond, done, helloworld)
  3. time.Sleep(time.Second)
  4. close(done)
  5. time.Sleep(time.Second)
  6. fmt.Println(&quot;Quitting&quot;)

This will output (try it on the Go Playground):

  1. 2009-11-10 23:00:00.3 +0000 UTC m=+0.300000001: Hello, World!
  2. 2009-11-10 23:00:00.6 +0000 UTC m=+0.600000001: Hello, World!
  3. 2009-11-10 23:00:00.9 +0000 UTC m=+0.900000001: Hello, World!
  4. Done!
  5. Quitting

huangapple
  • 本文由 发表于 2022年2月11日 19:51:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/71079646.html
匿名

发表评论

匿名网友

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

确定