我有一个功能列表及其各自的间隔。我想同时运行每个功能。
在JavaScript中,我写了类似以下内容:
maps.forEach(({fn, interval}) => {
setInterval(fn, interval)
})
如何在Golang中实现此功能?
答案 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上尝试这个。