英文:
Is there a way to do repetitive tasks at intervals?
问题
有没有一种方法可以在Go中执行重复的后台任务?我想要的是类似于Java中的Timer.schedule(task, delay, period)
。我知道可以使用goroutine和Time.sleep()
来实现这个,但我希望有一种更容易停止的方法。
这是我目前的代码,但我觉得它很丑陋。有没有更简洁/更好的方法?
func oneWay() {
var f func()
var t *time.Timer
f = func () {
fmt.Println("doing stuff")
t = time.AfterFunc(time.Duration(5) * time.Second, f)
}
t = time.AfterFunc(time.Duration(5) * time.Second, f)
defer t.Stop()
//模拟执行任务
time.Sleep(time.Minute)
}
英文:
Is there a way to do repetitive background tasks in Go? I'm thinking of something like Timer.schedule(task, delay, period)
in Java. I know I can do this with a goroutine and Time.sleep()
, but I'd like something that easily stopped.
Here's what I got, but looks ugly to me. Is there a cleaner/better way?
func oneWay() {
var f func()
var t *time.Timer
f = func () {
fmt.Println("doing stuff")
t = time.AfterFunc(time.Duration(5) * time.Second, f)
}
t = time.AfterFunc(time.Duration(5) * time.Second, f)
defer t.Stop()
//simulate doing stuff
time.Sleep(time.Minute)
}
答案1
得分: 319
The function time.NewTicker
makes a channel that sends a periodic message, and provides a way to stop it. Use it something like this (untested):
ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
go func() {
for {
select {
case <- ticker.C:
// do stuff
case <- quit:
ticker.Stop()
return
}
}
}()
You can stop the worker by closing the quit
channel: close(quit)
.
英文:
The function time.NewTicker
makes a channel that sends a periodic message, and provides a way to stop it. Use it something like this (untested):
ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
go func() {
for {
select {
case <- ticker.C:
// do stuff
case <- quit:
ticker.Stop()
return
}
}
}()
You can stop the worker by closing the quit
channel: close(quit)
.
答案2
得分: 59
如果您不关心时间偏移(取决于之前每次执行所花费的时间长短)并且不想使用通道,可以使用原生的range函数。
例如:
package main
import "fmt"
import "time"
func main() {
go heartBeat()
time.Sleep(time.Second * 5)
}
func heartBeat() {
for range time.Tick(time.Second * 1) {
fmt.Println("Foo")
}
}
英文:
If you do not care about tick shifting (depending on how long did it took previously on each execution) and you do not want to use channels, it's possible to use native range function.
i.e.
package main
import "fmt"
import "time"
func main() {
go heartBeat()
time.Sleep(time.Second * 5)
}
func heartBeat() {
for range time.Tick(time.Second * 1) {
fmt.Println("Foo")
}
}
答案3
得分: 32
package main
import (
"fmt"
"time"
)
func schedule(what func(), delay time.Duration) chan bool {
stop := make(chan bool)
go func() {
for {
what()
select {
case <-time.After(delay):
case <-stop:
return
}
}
}()
return stop
}
func main() {
ping := func() { fmt.Println("#") }
stop := schedule(ping, 5*time.Millisecond)
time.Sleep(25 * time.Millisecond)
stop <- true
time.Sleep(25 * time.Millisecond)
fmt.Println("Done")
}
英文:
How about something like
package main
import (
"fmt"
"time"
)
func schedule(what func(), delay time.Duration) chan bool {
stop := make(chan bool)
go func() {
for {
what()
select {
case <-time.After(delay):
case <-stop:
return
}
}
}()
return stop
}
func main() {
ping := func() { fmt.Println("#") }
stop := schedule(ping, 5*time.Millisecond)
time.Sleep(25 * time.Millisecond)
stop <- true
time.Sleep(25 * time.Millisecond)
fmt.Println("Done")
}
答案4
得分: 26
请查看这个库:https://github.com/robfig/cron
以下是示例代码:
c := cron.New()
c.AddFunc("0 30 * * * *", func() { fmt.Println("每小时的半点") })
c.AddFunc("@hourly", func() { fmt.Println("每小时") })
c.AddFunc("@every 1h30m", func() { fmt.Println("每小时三十分钟") })
c.Start()
英文:
Check out this library: https://github.com/robfig/cron
Example as below:
c := cron.New()
c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })
c.AddFunc("@hourly", func() { fmt.Println("Every hour") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
c.Start()
答案5
得分: 10
如果你想在任何时刻停止它 ticker
ticker := time.NewTicker(500 * time.Millisecond)
go func() {
for range ticker.C {
fmt.Println("Tick")
}
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()
如果你不想停止它 tick:
tick := time.Tick(500 * time.Millisecond)
for range tick {
fmt.Println("Tick")
}
英文:
If you want to stop it in any moment ticker
ticker := time.NewTicker(500 * time.Millisecond)
go func() {
for range ticker.C {
fmt.Println("Tick")
}
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()
If you do not want to stop it tick:
tick := time.Tick(500 * time.Millisecond)
for range tick {
fmt.Println("Tick")
}
答案6
得分: 4
我使用以下代码:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("\n今天:", now)
after := now.Add(1 * time.Minute)
fmt.Println("\n加1分钟:", after)
for {
fmt.Println("测试")
time.Sleep(10 * time.Second)
now = time.Now()
if now.After(after) {
break
}
}
fmt.Println("完成")
}
对我来说,这更简单且运行良好。
英文:
I use the following code:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("\nToday:", now)
after := now.Add(1 * time.Minute)
fmt.Println("\nAdd 1 Minute:", after)
for {
fmt.Println("test")
time.Sleep(10 * time.Second)
now = time.Now()
if now.After(after) {
break
}
}
fmt.Println("done")
}
It is more simple and works fine to me.
答案7
得分: 3
对于这个问题的更广泛的回答可能考虑到Occam中经常使用的乐高积木方法,并通过JCSP提供给Java社区。关于这个想法,有一个非常好的Peter Welch的演讲。
这种即插即用的方法直接转化为Go语言,因为Go使用与Occam相同的通信顺序进程基础知识。
因此,当涉及到设计重复任务时,您可以将系统构建为由简单组件(如goroutine)组成的数据流网络,这些组件通过通道交换事件(即消息或信号)。
这种方法是组合的:每个小组件组可以自身作为一个更大的组件行为,无限循环。这非常强大,因为复杂的并发系统是由易于理解的积木构建而成。
脚注:在Welch的演讲中,他使用Occam语法表示通道,即*!和?,这直接对应于Go语言中的ch<-和<-ch**。*
英文:
A broader answer to this question might consider the Lego brick approach often used in Occam, and offered to the Java community via JCSP. There is a very good presentation by Peter Welch on this idea.
This plug-and-play approach translates directly to Go, because Go uses the same Communicating Sequential Process fundamentals as does Occam.
So, when it comes to designing repetitive tasks, you can build your system as a dataflow network of simple components (as goroutines) that exchange events (i.e. messages or signals) via channels.
This approach is compositional: each group of small components can itself behave as a larger component, ad infinitum. This can be very powerful because complex concurrent systems are made from easy to understand bricks.
Footnote: in Welch's presentation, he uses the Occam syntax for channels, which is ! and ? and these directly correspond to ch<- and <-ch in Go.
答案8
得分: 3
你可以像这样简单地使用gocron包:
package main
import (
"fmt"
"time"
// go get github.com/go-co-op/gocron
"github.com/go-co-op/gocron"
)
func main() {
s := gocron.NewScheduler(time.UTC)
s.Every(3).Seconds().Do(func() { fmt.Println("Every 3 seconds") })
// 你可以以两种不同的方式开始运行调度器:
// 异步地启动调度器
s.StartAsync()
// 启动调度器并阻塞当前执行路径
// s.StartBlocking()
}
gocron: https://github.com/go-co-op/gocron
英文:
You can simply use gocron package like this:
package main
import (
"fmt"
"time"
// go get github.com/go-co-op/gocron
"github.com/go-co-op/gocron"
)
func main() {
s := gocron.NewScheduler(time.UTC)
s.Every(3).Seconds().Do(func() { fmt.Println("Every 3 seconds") })
// you can start running the scheduler in two different ways:
// starts the scheduler asynchronously
s.StartAsync()
// starts the scheduler and blocks current execution path
// s.StartBlocking()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论