有没有办法在Golang中每隔一段时间做一次重复的任务?

Ste*_*isk 140 go

有没有办法在Go中执行重复的后台任务?我在考虑类似Timer.schedule(task, delay, period)Java 的东西.我知道我可以用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)
}
Run Code Online (Sandbox Code Playgroud)

Pau*_*kin 219

该函数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
        }
    }
 }()
Run Code Online (Sandbox Code Playgroud)

您可以通过关闭quit频道来停止工作人员:close(quit).

  • @ bk0,时间通道不"备份"(文档说"它调整间隔或下降滴答以弥补慢速接收器").给定的代码完全按照你的说法运行(最多运行一个任务); 如果任务需要很长时间,则下一次调用将被延迟; 不需要互斥锁.相反,如果希望每个间隔开始一个新任务(即使前一个没有完成),那么只需使用`go func(){/*do stuff*/}()`. (9认同)
  • 答案是不正确的,这取决于OP想要什么.如果OP想要定期执行而不管工作人员使用多少时间,则必须在go例程中运行`do stuff`,否则下一个worker将立即执行(当需要超过5秒时). (8认同)
  • @SteveBrisk参见[该文档](http://golang.org/pkg/time/#Ticker.Stop).如果频道已关闭,则读取只会成功,您可能不希望这样. (4认同)
  • 停止自动收报机工作,但goroutine永远不会被垃圾收集. (3认同)
  • IMO,当你想要停止调度程序时,你应该"关闭(退出)`. (2认同)

Vol*_*ker 23

怎么样的

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")
}
Run Code Online (Sandbox Code Playgroud)

操场

  • @Dustin如果你想在任务的结束和开始之间执行固定的差距,这样会更好.两者都不是最好的 - 这是两个不同的用例. (4认同)
  • `time.Ticker`比'time.After`更好,你希望按计划保持任务与执行之间的任意差距. (3认同)

Ale*_*ekc 22

如果你不关心滴答移位(取决于每次执行之前花了多长时间)并且你不想使用通道,则可以使用原生范围功能.

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

操场


Bro*_*Lin 17

看看这个库: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()
Run Code Online (Sandbox Code Playgroud)


Joh*_*ias 11

如果您想随时停止

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

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

tick := time.Tick(500 * time.Millisecond)
for range tick {
    fmt.Println("Tick")
}
Run Code Online (Sandbox Code Playgroud)