関連記事
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
を指定した版は、コアが一つしか使えないので、非同期処理が並列で走ることができなくなっています。なので、結果がバラけずに順に出てくるということになります。
参考情報
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。