运行 在 Go 中每隔一定时间并发执行多个函数
Run multiple functions concurrently at intervals in Go
我有一个函数列表和它们各自的间隔。我想 运行 每个函数在其间隔内同时运行。
在JavaScript中,我写了这样的东西:
maps.forEach(({fn, interval}) => {
setInterval(fn, interval)
})
如何在 Golang 中实现此功能?
使用 time.Ticker
to receive "events" periodically, which you may use to time the execution of a function. You may obtain a time.Ticker
by calling time.NewTicker()
。 returned 自动收报机有一个定期发送值的通道。
使用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
语句到 "monitor" 代码的通道和这个 done
通道,如果从 done
成功接收 return。
例如:
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 上试试这个。
请注意,即使在这个简单的示例中没有必要停止自动收报机(因为 ),但在现实生活中,如果应用程序继续 运行,不停止自动收报机会浪费资源(他们将继续使用后台 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 上试试这个。
我有一个函数列表和它们各自的间隔。我想 运行 每个函数在其间隔内同时运行。
在JavaScript中,我写了这样的东西:
maps.forEach(({fn, interval}) => {
setInterval(fn, interval)
})
如何在 Golang 中实现此功能?
使用 time.Ticker
to receive "events" periodically, which you may use to time the execution of a function. You may obtain a time.Ticker
by calling time.NewTicker()
。 returned 自动收报机有一个定期发送值的通道。
使用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
语句到 "monitor" 代码的通道和这个 done
通道,如果从 done
成功接收 return。
例如:
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 上试试这个。
请注意,即使在这个简单的示例中没有必要停止自动收报机(因为
遗言:
如果您有一段函数区间对,只需使用一个循环将每一对传递给这个 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 上试试这个。