Go言語による並行処理に知らない書き方があったのでメモ。
TL;DR
time.Tick()
をfor range
で使うとスマートに無限ループが書ける- x秒間だけn秒おきになにかするループは
time.Tick()
使わないほうがシンプルな気がする
n秒おきになにかする無限ループ
forループとtim.Sleep()で書くとき
x秒おきに何かをする無限ループを書くときこんなfor
ループを書きがちだった。
(playgroundのサンプルコードは途中で終わるようにカウンタを入れている。)
https://play.golang.org/p/Do7e6enUu5z
package main
import (
"fmt"
"time"
)
func main() {
for {
fmt.Println("Tick!!")
time.Sleep(3 * time.Millisecond)
}
}
time.Tickを使ってX秒おきに無限ループ
time.Tick
を使えば以下のようにも書ける。
https://play.golang.org/p/VlWP05XLRGX
package main
import (
"fmt"
"time"
)
func main() {
for range time.Tick(3 * time.Millisecond) {
fmt.Println("Tick!!")
}
}
x秒間だけn秒おきになにかする有限ループ
特定の時間の間だけ定期的に何かをするサンプルコードもGo言語による並行処理に載っていた。
https://play.golang.org/p/O4KWXe5KQJJ
package main
import (
"fmt"
"time"
)
func main() {
limit := 5 * time.Millisecond
// time.Since()で取得したDurationでループを止めるか決める
for begin := time.Now(); time.Since(begin) < limit; {
fmt.Println("Tick!!")
time.Sleep(1 * time.Millisecond)
}
}
time.Tick
を使うとこんな感じ?これは素直に上の書き方をしたほうがシンプルだとおもう。
https://play.golang.org/p/8NxMqbqcmX5
package main
import (
"fmt"
"time"
)
func main() {
limit := 5 * time.Millisecond
begin := time.Now()
for now := range time.Tick(1 * time.Millisecond) {
fmt.Println("Tick!!")
// time.Tickで取得した現在時間とループ開始直前の時間の差分でループを止めるか決める
if now.Sub(begin) >= limit {
break
}
}
}
終わりに
time.Tick()
は内部的にはtime.Ticker
を生成している。
time.Ticker
を使うときは明示的にStop()
を呼ばないとリークするらしいが、time.Tick()
をrange
で使っている場合はループのスコープが外れればGCされるのかな?
https://golang.org/src/time/tick.go?s=1752:1785#L44
func Tick(d Duration) <-chan Time {
if d <= 0 {
return nil
}
return NewTicker(d).C
}
参考
- Goで一定周期で何かを行う方法
- time.Tick() を for ループの中に書いてはいけない