アトミック操作
分割不可能(アトミック)な単一の操作のこと
サポート言語
Go: sync/atomic パッケージに集約されている
整数などの単純な変数の値を更新するだけならば、mutex を用いるよりも効率的に処理できる
∵ mutex はプログラムの一部を逐次処理にしてしまうため
warning.icon
複数の変数を同時に更新することはできない
通常の方法で変数を更新した方が、アトミック操作で変数を更新した場合よりもはるかに高速
∵ コンパイラ や CPU の最適化が無効になるため
e.g.
通常、CPU は頻繁にアクセスする変数をキャッシュに保持し、処理を高速化する
しかし、キャッシュの容量には限りがあるため、必要に応じて変数の内容を メインメモリ に書き戻す(フラッシュ)することがある
一方アトミック操作の場合、並列で動作する他の スレッド が変数の更新を確実に確認できるようにする必要がある
そのため、CPU はキャッシュの一貫性(キャッシュコヒーレンシ)を維持する必要がある
これを実現するために、必要に応じて メインメモリ に書き戻したり、他の CPU がキャッシュしているデータを無効化するにしたりすることがある
Go での ベンチマーク 測定
code:go
var total = int64(0)
func BenchmarkNormal(bench *testing.B) {
for range bench.N {
total += 1
}
}
func BenchmarkAtomic(bench *testing.B) {
for range bench.N {
atomic.AddInt64(&total, 1)
}
}
結果
code:sh
$ go test -bench=. -count 3
goos: darwin
goarch: arm64
pkg: listing12_3
cpu: Apple M2 Max
BenchmarkNormal-12 538361530 1.987 ns/op
BenchmarkNormal-12 606458019 1.965 ns/op
BenchmarkNormal-12 603949323 1.975 ns/op
BenchmarkAtomic-12 308510485 3.907 ns/op
BenchmarkAtomic-12 303942386 3.967 ns/op
BenchmarkAtomic-12 307332045 3.837 ns/op
PASS
ok listing12_3 9.182s