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

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

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 &lt;-done:
			fmt.Println(&quot;Done!&quot;)
			return
		case t := &lt;-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(&quot;Quitting&quot;)

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

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:

确定