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

时间:2013-05-09 16:13:14

标签: go

有没有办法在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)
}

7 个答案:

答案 0 :(得分:201)

函数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)

答案 1 :(得分:21)

这样的东西
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

答案 2 :(得分:18)

如果您不关心嘀嗒变换(取决于每次执行之前花费的时间)并且您不想使用频道,则可以使用本机范围功能。

即。

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

答案 3 :(得分:15)

查看此库:https://github.com/robfig/cron

示例如下:

class Class1 {
}

class Class2 {
    var myOp: Class1?
}

func myFunc(c: Class2) -> AnyObject {
    if let c1 = c.myOp{
        return c1.self
    }
    return c
}

var object = Class2()
object.myOp = Class1()
myFunc(object) // Class1

答案 4 :(得分:3)

对这个问题的更广泛的回答可能会考虑在Occam中经常使用的乐高积木方法,并通过JCSP提供给Java社区。这个想法非常好presentation by Peter Welch

这种即插即用方法直接转换为Go,因为Go使用与Occam相同的Communicating Sequential Process基础。

因此,在设计重复性任务时,您可以将系统构建为通过通道交换事件(即消息或信号)的简单组件(如goroutine)的数据流网络。

这种方法是组合的:每组小组件本身都可以表现为更大的组件,无限制。这可能非常强大,因为复杂的并发系统是由易于理解的砖块组成的。

脚注:在Welch的演讲中,他使用Occam语法进行频道,,这些直接对应于 ch&lt; - &lt; -ch 在Go。

答案 5 :(得分:3)

我使用以下代码:

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

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

答案 6 :(得分:0)

如果您想随时停止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")
}