Go语言 有没有一种方法可以让你每隔一段时间做一次重复性的任务?

hfwmuf9z  于 2023-09-28  发布在  Go
关注(0)|答案(8)|浏览(103)

有没有一种方法可以在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()

    //simulate doing stuff
    time.Sleep(time.Minute)
}
qmb5sa22

qmb5sa221#

函数time.NewTicker创建了一个发送周期性消息的通道,并提供了一种停止它的方法。这样使用它(未经测试):

ticker := time.NewTicker(5 * time.Second)
quit := make(chan struct{})
go func() {
    for {
       select {
        case <- ticker.C:
            // do stuff
        case <- quit:
            ticker.Stop()
            return
        }
    }
 }()

您可以通过关闭quit通道来停止工作进程:close(quit)

jdgnovmf

jdgnovmf2#

如果你不关心tick shifting(取决于每次执行之前花了多长时间),并且你不想使用通道,那么可以使用本机范围函数。

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")
    }
}

Playground

zzlelutf

zzlelutf3#

比如说

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")
}

Playground

elcex8rz

elcex8rz4#

看看这个图书馆:https://github.com/robfig/cron
示例如下:

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()
ercv8c1e

ercv8c1e5#

如果你想在任何时候停止它ticker

ticker := time.NewTicker(500 * time.Millisecond)
go func() {
    for range ticker.C {
        fmt.Println("Tick")
    }
}()
time.Sleep(1600 * time.Millisecond)
ticker.Stop()

如果您不想停止它,请勾选:

tick := time.Tick(500 * time.Millisecond)
for range tick {
    fmt.Println("Tick")
}
u5rb5r59

u5rb5r596#

我使用以下代码:

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Println("\nToday:", now)

    after := now.Add(1 * time.Minute - time.Second)
    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")
}

它更简单,对我来说效果很好。

uqzxnwby

uqzxnwby7#

对这个问题的更广泛的回答可能是考虑Occam中经常使用的乐高积木方法,并通过JCSP提供给Java社区。有一个非常好的presentation by Peter Welch关于这个想法。
这种即插即用的方法直接转化为Go语言,因为Go语言使用与Occam相同的通信顺序过程基础。
因此,当涉及到设计重复性任务时,您可以将系统构建为一个简单组件(如goroutine)的简单网络,这些组件交换事件(即,消息或信号)。
这种方法是组合的:每组小组件本身可以作为更大的组件,直到无限。这可能非常强大,因为复杂的并发系统是由易于理解的砖块组成的。

  • 脚注:在Welch的演示中,他使用了通道的Occam语法,即**!直接对应于Go中的ch<-<-ch**。
ehxuflar

ehxuflar8#

你可以像这样简单地使用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") })
 // 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()
}

gocron:https://github.com/go-co-op/gocron

相关问题