LoginSignup
2
1

More than 5 years have passed since last update.

Go で N 秒に M 回なんかする

Posted at

なんかするコマンド

  • 一定の間隔でなんかしたいときは time.Ticker が便利
ticker.go
package main

import (
    "flag"
    "fmt"
    "os/exec"
    "strings"
    "time"
)

var (
    s = flag.Int("s", 1, "unit seconds")
    c = flag.Int("c", 1, "unit count")
    d = flag.Int("d", 1, "duration seconds")
    e = flag.String("e", "", "execute command")
)

func main() {
    flag.Parse()

    ticker := time.NewTicker(time.Second * time.Duration(*s) / time.Duration(*c))
    defer ticker.Stop()

    done := make(chan bool)
    go func() {
        time.Sleep(time.Second * time.Duration(*d))
        done <- true
    }()

    e := strings.Split(*e, " ")

    for {
        select {
        case <-done:
            return
        case <-ticker.C:
            if out, err := exec.Command(e[0], e[1:]...).Output(); err != nil {
                panic(err)
            } else {
                fmt.Printf("%s", out)
            }
        }
    }
}

やる

# 1 秒に 10 回のペースで 5 秒間 echo hello world する
$ go run ticker.go -s 1 -c 10 -e "echo hello world" -d 5

# 1 秒に 1000 回ペースを指定するが exec が遅いので自分の環境だと秒間 360 回程度しか実行できない
$ go run ticker.go -s 1 -c 1000 -e "echo hello world" -d 5 | wc
1837    3674   22044

Go でなんかする

  • コマンド実行だと遅いので実処理部分を Go で実装する
  • ここでは任意のファイルに任意の長さのログを書き出すスクリプトを作る
ticker2.go
package main

import (
    "bytes"
    "flag"
    "os"
    "time"
)

var (
    s = flag.Int("s", 1, "unit seconds")
    c = flag.Int("c", 1, "unit count")
    d = flag.Int("d", 1, "duration seconds")
    f = flag.String("f", "", "log filename")
    l = flag.Int("l", 1, "log length")
)

func main() {
    flag.Parse()

    ticker := time.NewTicker(time.Second * time.Duration(*s) / time.Duration(*c))
    defer ticker.Stop()

    fd, err := os.OpenFile(*f, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        panic(err)
    }
    defer fd.Close()
    txt := append(bytes.Repeat([]byte("0"), *l), []byte("\n")...)

    done := make(chan bool)
    go func() {
        time.Sleep(time.Second * time.Duration(*d))
        done <- true
    }()

    for {
        select {
        case <-done:
            return
        case <-ticker.C:
            if _, err := fd.Write(txt); err != nil {
                panic(err)
            }
        }
    }
}

Go でやる


# 1000 件/秒で 1 秒間 500(499 + 改行) バイトのログを out.log ファイルに出力する
$ go run ticker.go -s 1 -c 1000 -d 1 -f out.log -l 499

# 毎秒 1000 件程度は楽勝
$ wc out.log
    1000    1000  500000 out.log

# 100000 件/秒で 1 秒間 500 バイトのログを out.log ファイルに出力する
$ go run ticker.go -s 1 -c 100000 -d 1 -f out2.log -l 499

# 自分の環境だと毎秒 7, 8 万件程度まで実行できた
$ wc out2.log
   72853   72853 36426500 out2.log

どっかでなんかやる

  • Go なので Docker や Kubernetes 環境とかの Linux 向けにポータブルにビルドして実行するのが楽
# Linux 向けにビルド
GOOS=linux GOARCH=amd64 go build ticker.go

# Docker で実行
docker cp ticker $CONTAINER_ID:/path/to/ticker
docker exec $CONTAINER_ID sh -c '/path/to/ticker -s 1 -c 10 -e "echo hello world" -d 5'

# Kubernetes で実行
kubectl cp ./ticker $POD_NAME:/path/to/ticker
kubectl exec $POD_NAME -- /path/to/ticker -s 1 -c 10 -e "echo hello world" -d 5
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1