いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-78 (指定したインターバルでデータを出力するチャネル, Interval)

概要

引き続き、小ネタチャネル関数の続き。( #関連記事 参照)

たまに処理をするたびに一定時間のインターバルを置いておきたいときがあったりします。

たいてい以下のように書くと思います。

for v := range Take(Repeat(1)) {
  // v を使って何か処理
  <-time.After(100 * time.Millisecond)
}

time.Sleep() 使っても同じです。で、パイプラインで以下の様にしたいって思いました。

for v := range Interval(Take(Repeat(1)), 100 * time.Millisecond) {
  // v を使って何か処理
}

サンプル

package chans

import (
    "time"
)

// Interval -- 指定した間隔でデータを出力していくチャネルを生成します。
func Interval(done <-chan struct{}, in <-chan interface{}, interval time.Duration) <-chan interface{} {
    out := make(chan interface{})

    go func() {
        defer close(out)

        for v := range OrDone(done, in) {
            select {
            case out <- v:
                <-time.After(interval)
            case <-done:
            }
        }
    }()

    return out
}

gomy/interval.go at master · devlights/gomy · GitHub

以下テストコードです。

package chans

import (
    "testing"
    "time"
)

func TestInterval(t *testing.T) {
    type (
        testin struct {
            input    []interface{}
            interval time.Duration
        }
        testout struct {
            estimation time.Duration
        }
        testcase struct {
            in  testin
            out testout
        }
    )

    cases := []testcase{
        {
            in: testin{
                input:    []interface{}{1, 2, 3, 4, 5},
                interval: 10 * time.Millisecond,
            },
            out: testout{estimation: (10*5 + 10) * time.Millisecond},
        },
        {
            in: testin{
                input:    []interface{}{1, 2, 3, 4, 5},
                interval: 100 * time.Millisecond,
            },
            out: testout{estimation: (100*5 + 10) * time.Millisecond},
        },
        {
            in: testin{
                input:    []interface{}{1, 2, 3, 4, 5},
                interval: 1000 * time.Millisecond,
            },
            out: testout{estimation: (1000*5 + 10) * time.Millisecond},
        },
    }

    for caseIndex, c := range cases {
        func() {
            done := make(chan struct{})
            defer close(done)

            start := time.Now()
            var lastElapsed time.Duration
            for v := range Interval(done, ForEach(done, c.in.input...), c.in.interval) {
                lastElapsed = time.Since(start)
                t.Logf("[test-%02d] %v (%v)", caseIndex, v, lastElapsed)
            }

            if c.out.estimation < lastElapsed {
                t.Errorf("want: <= %v\tgot: %v", c.out.estimation, lastElapsed)
            }
        }()
    }
}

実行すると以下のようになります。

$ go test -v github.com/devlights/gomy/chans -run ^TestInterval.*$
=== RUN   TestInterval
    TestInterval: interval_test.go:56: [test-00] 1 (0s)
    TestInterval: interval_test.go:56: [test-00] 2 (10.1761ms)
    TestInterval: interval_test.go:56: [test-00] 3 (20.3089ms)
    TestInterval: interval_test.go:56: [test-00] 4 (30.4745ms)
    TestInterval: interval_test.go:56: [test-00] 5 (40.5546ms)
    TestInterval: interval_test.go:56: [test-01] 1 (0s)
    TestInterval: interval_test.go:56: [test-01] 2 (100.7949ms)
    TestInterval: interval_test.go:56: [test-01] 3 (200.8851ms)
    TestInterval: interval_test.go:56: [test-01] 4 (301.789ms)
    TestInterval: interval_test.go:56: [test-01] 5 (401.1778ms)
    TestInterval: interval_test.go:56: [test-02] 1 (0s)
    TestInterval: interval_test.go:56: [test-02] 2 (1.0008048s)
    TestInterval: interval_test.go:56: [test-02] 3 (2.0015159s)
    TestInterval: interval_test.go:56: [test-02] 4 (3.0022897s)
    TestInterval: interval_test.go:56: [test-02] 5 (4.003209s)
--- PASS: TestInterval (5.56s)
PASS
ok      github.com/devlights/gomy/chans 5.670s

ちゃんと、指定時間待機した後にデータが出力されていますね。

参考

Go言語による並行処理

Go言語による並行処理

関連記事

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com

devlights.hatenablog.com


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com