在Go中间隔并发运行多个功能

时间:2018-09-18 08:03:38

标签: go timer scheduler

我有一个功能列表及其各自的间隔。我想同时运行每个功能。

在JavaScript中,我写了类似以下内容:

maps.forEach(({fn, interval}) => {
    setInterval(fn, interval)
})

如何在Golang中实现此功能?

1 个答案:

答案 0 :(得分:7)

使用time.Ticker定期接收“事件”,您可以使用它们来定时执行函数。您可以通过调用time.NewTicker()获得time.Ticker。返回的股票行情有一个定期发送值的通道。

使用goroutine连续接收事件并调用函数,例如for range循环。

让我们看看2个功能:

func oneSec() {
    log.Println("oneSec")
}

func twoSec() {
    log.Println("twoSec")
}

这是一个简单的调度程序,它定期调用给定的函数:

func schedule(f func(), interval time.Duration) *time.Ticker {
    ticker := time.NewTicker(interval)
    go func() {
        for range ticker.C {
            f()
        }
    }()
    return ticker
}

使用示例:

func main() {
    t1 := schedule(oneSec, time.Second)
    t2 := schedule(twoSec, 2*time.Second)
    time.Sleep(5 * time.Second)
    t1.Stop()
    t2.Stop()
}

示例输出(在Go Playground上尝试):

2009/11/10 23:00:01 oneSec
2009/11/10 23:00:02 twoSec
2009/11/10 23:00:02 oneSec
2009/11/10 23:00:03 oneSec
2009/11/10 23:00:04 twoSec
2009/11/10 23:00:04 oneSec

请注意,Ticker.Stop()不会关闭股票行情的频道,因此for range不会终止; Stop()仅停止在股票行情的频道上发送值。

如果要终止用于安排函数调用的goroutine,可以使用其他通道进行。然后,这些goroutine可以使用select语句来“监视”股票行情的频道和此done频道,如果从done接收成功,则返回。

例如:

func schedule(f func(), interval time.Duration, done <-chan bool) *time.Ticker {
    ticker := time.NewTicker(interval)
    go func() {
        for {
            select {
            case <-ticker.C:
                f()
            case <-done:
                return
            }
        }
    }()
    return ticker
}

并使用它:

func main() {
    done := make(chan bool)
    t1 := schedule(oneSec, time.Second, done)
    t2 := schedule(twoSec, 2*time.Second, done)
    time.Sleep(5 * time.Second)
    close(done)
    t1.Stop()
    t2.Stop()
}

Go Playground上尝试这个。

请注意,即使在此简单示例中(由于when the main goroutine ends, so does the program with it,也不必停止股票行情),但在实际示例中,如果应用继续运行,则停止股票行情会浪费资源(它们将继续使用后台goroutine,并将继续尝试在其通道上发送值。

姓氏:

如果您有一组函数间隔对,只需使用循环将每个对传递给此schedule()函数。像这样:

type pair struct {
    f        func()
    interval time.Duration
}

pairs := []pair{
    {oneSec, time.Second},
    {twoSec, 2 * time.Second},
}

done := make(chan bool)
ts := make([]*time.Ticker, len(pairs))
for i, p := range pairs {
    ts[i] = schedule(p.f, p.interval, done)
}

time.Sleep(5 * time.Second)
close(done)

for _, t := range ts {
    t.Stop()
}

Go Playground上尝试这个。