我有一个功能列表和它们各自的间隔.我想同时以其间隔运行每个函数.
在JavaScript中,我写了类似的东西:
maps.forEach(({fn, interval}) => { setInterval(fn, interval) })
如何在Golang中实现此功能?
使用a time.Ticker
定期接收"事件",您可以使用它来计算函数的执行时间.您可以time.Ticker
通过电话获得time.NewTicker()
.返回的自动收报机有一个定期发送值的通道.
使用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()
只停止在自动收报机的频道上发送值.
如果要终止用于计划函数调用的goroutines,可以使用其他通道执行此操作.然后那些goroutines可以使用一个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尝试这个.
请注意,即使在这个简单的示例中不需要停止代码(因为当main
goroutine结束时,程序也随之结束),在实际示例中,如果应用程序继续运行,留下代码不会浪费资源(他们将继续使用背景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尝试这个.