いろいろ備忘録日記

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

特定のCPUコアでプログラムを実行する (linux, taskset)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。よく忘れるのでここにメモメモ。。。

特定のCPUコアでプログラムを動かしたいときがたまにあります。非同期系の処理を書いていてデバッグしたいときとか。

linuxの場合は、taskset というコマンドがありますので、CPUアフィニティ(どのCPUコアで実行されるか)が設定できます。

普段使うことはそうそう無いですが、いざって時に知っていると少し便利です。

サンプル

複数の非同期処理があり、それぞれが一つのデータソースに書き込むという処理をとりあえず用意。

どの言語でも良いのですが、以下はとりあえずGoで実装してます。

package main

import (
    "fmt"
    "os"
    "runtime"
    "sync"
)

const (
    LOOP_COUNT = 5
)

func init() {
    fmt.Printf("GOMAXPROC=%d\n", runtime.GOMAXPROCS(0))
}

func main() {
    var (
        ch = make(chan string)
        wg = sync.WaitGroup{}
        fn = func(wg *sync.WaitGroup, ch chan<- string, prefix int) {
            defer wg.Done()
            for i := 0; i < LOOP_COUNT; i++ {
                ch <- fmt.Sprintf("t%d: %d", prefix, i)
            }
        }
    )

    wg.Add(3)

    go fn(&wg, ch, 1)
    go fn(&wg, ch, 2)
    go fn(&wg, ch, 3)

    go func() {
        defer close(ch)
        wg.Wait()
    }()

    for v := range ch {
        fmt.Fprintln(os.Stderr, v)
    }
}

これを普通に実行すると、例えば以下のようになります。

$ task
task: [build] go mod tidy
task: [build] go build -o app main.go
task: [run] ./app
GOMAXPROC=16
t2: 0
t2: 1
t1: 0
t1: 1
t3: 0
t2: 2
t1: 2
t3: 1
t2: 3
t1: 3
t3: 2
t3: 3
t3: 4
t2: 4
t1: 4

それぞれがバラバラに書き込んでいますね。これはそれぞれの非同期処理が個別のCPUコア上で実行されているためです。

んで、例えばですが、このような非同期処理をデバッグしたいときって、このままじゃちょっとシンドい場合があります。

なので、一旦シングルスレッド状態にして動かしてしまいたい。

そのような場合に、taskset コマンドさんが役に立ってくれます。

今度は taskset コマンド付きで実行します。

$ taskset -c 0 ./app
GOMAXPROC=1
t1: 0
t1: 1
t1: 2
t1: 3
t1: 4
t2: 0
t2: 1
t2: 2
t2: 3
t2: 4
t3: 0
t3: 1
t3: 2
t3: 3
t3: 4

オプションの -c はCPUコアのインデックスを指定します。配列と同じでゼロ始まりです。今は 0 だけ指定したので コア0 だけを使ってプログラムを実行してとお願いした形ですね。

複数指定したい場合は -c 0,1,2 のように指定します。

上記の taskset を指定した版は、コアが一つしか使えないので、非同期処理が並列で走ることができなくなっています。なので、結果がバラけずに順に出てくるということになります。

参考情報

man7.org

pkg.go.dev


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

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