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 ループの中に書いてはいけない