Go
golang

Golangで周期的に実行するときのパターン

(contextを使ってキャンセルするパターンを追記しました。)

周期的な実行のトリガーにはtime.Tickerを使用します。
例えば、doPeriodically()を100msec間隔で実行したいときは以下のようにします。

package main

import (
    "log"
    "time"
)

func main() {
    log.SetFlags(log.Lmicroseconds)
    ticker := time.NewTicker(time.Millisecond * 100)
    defer ticker.Stop()
    count := 0
    for {
        select {
        case <-ticker.C:
            log.Printf("count=%d\n", count)
            count++
            doPeriodically()
        }
    }
}

func doPeriodically() {
    /* do something */
}

2018.2.16 追記

defer ticker.Stop() を追加しました
この例ではあってもなくても変わらないのですが、forループを何かの条件で抜けるようにしたときには必要になるので。

参考

もっといい記事をこれ書いた後で見つけてしまいました。
Goで一定周期で何かを行う方法

contextによるキャンセル付き (2018.3.13 追記)

func doPeriodically(t time.Time) {
    /* do something */
}

func periodicLoop(ctx context.Context, interval time.Duration) {
    ticker := time.NewTicker(interval)
    defer ticker.Stop()
    doPeriodically(time.Now())
    for {
        select {
        case <-ctx.Done():
            return
        case t := <-ticker.C:
            doPeriodically(t)
        }
    }
}

mainでは以下のようにctxを作成して、periodicLoopに渡し、止めたいときにcancel()を呼びます。

func main() {
    ...

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    go periodicLoop(ctx, 2*time.Second)

    /* call cancel() to stop */
}