golangで定期処理などを書きたくなったのでどうやって書くか考えます。
とりあえずtimeパッケージかcontextパッケージあたりを使うと良さそうなので2つとも使ってみます。
timeパッケージ使用
goroutineとtimeパッケージで割と簡単に書くことができました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
func somefunc() { log.Println("somefunc") } func anyfunc() { log.Println("anyfunc") } func timeout(sec int, fn func()) { time.Sleep(time.Duration(sec) * time.Second) fn() } func interval(sec int, fn func()) { t := time.NewTicker(time.Duration(sec) * time.Second) defer t.Stop() for { select { case <-t.C: fn() } } } func main() { go interval(5, somefunc) go timeout(8, anyfunc) //wait for os signal sc := make(chan os.Signal, 1) signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) <-sc log.Println("syscalled") } |
main
の後半は「Ctrl+C」などで終了するのを待っている処理です。
タイムアウトはSleep
で処理を待っていて、インターバルは無限ループ内でTiker
の受信を待っています。
contextパッケージ使用
インターバル処理のキャンセルなどしたい場合はcontext
パッケージを使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
func main() { //10秒で終わるコンテキストを作る ctx := context.Background() ctx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() //3秒ごとに関数実行 go ctxInterval(ctx, 3, somefunc) select { case <-ctx.Done(): log.Println("ctx end") log.Println(ctx.Err()) } } func ctxInterval(ctx context.Context, sec int, fn func()) { _ctx, cancel := context.WithCancel(ctx) defer cancel() L: for { time.Sleep(time.Duration(sec) * time.Second) select { case <-_ctx.Done(): log.Println("_ctx end!") break L default: fn() } } } |
この場合main
のselect
はdefault
を指定していないため待機状態になっています。
“_ctx end!”の方が表示されていませんが、これは子のコンテキストがスリープ中に親が終了して、伝播する前に全体の処理が終わってしまったためです。
ちょっとごちゃごちゃして取っ付きにくいですが、思ったよりシンプルな動きみたいで使いやすそうです。