1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

atomic, mutex どうなんだろう・・・ mutex が早いだと・・・ ニャ

Last updated at Posted at 2020-01-19

所感

ちゃんと調べないとダメそう・・・
Lock 有りが何もしないより早いなんて・・・

概要

var num int64
num++

単純な数字カウントアップ atomic が早そうだなーなのでベンチマーク撮ってみよ

  • 何もせずに num++
  • mutex.Loc() num++ mutex.Unlock()
  • atomic.AddInt64
  • atomic.ValueLoad(), Store()

コード

カウントアップ

main.go
import (
	"sync"
	"sync/atomic"
)

var mutex sync.Mutex
var value atomic.Value

type Counter int64

func (c *Counter) Inc() {
	*c++
}

func (c *Counter) AtomicInc() {
	atomic.AddInt64((*int64)(c), 1)
}

func (c *Counter) LockInc() {
	mutex.Lock()
	defer mutex.Unlock()
	*c++
}

func incValue() {
	cnt := value.Load().(Counter)
	cnt++
	value.Store(cnt)
}

func countup(inc func(), n int) {
	var wg sync.WaitGroup
	for i := 0; i < n; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			inc()
		}()
	}
	wg.Wait()
}

ベンチマーク

main_test.go
package main

// go test -bench . | grep 'ns/op'

import (
	"testing"
)

func BenchmarkInc_Countup(b *testing.B) {
	var cnt Counter
	b.ResetTimer()
	countup(cnt.Inc, b.N)
	b.Logf("%d -> %d", b.N, cnt)
}

func BenchmarkLock_Countup(b *testing.B) {
	var cnt Counter
	b.ResetTimer()
	countup(cnt.LockInc, b.N)
	b.Logf("%d -> %d", b.N, cnt)
}

func BenchmarkAtomic_Countup(b *testing.B) {
	var cnt Counter
	b.ResetTimer()
	countup(cnt.AtomicInc, b.N)
	b.Logf("%d -> %d", b.N, cnt)
}

func BenchmarkAtomicValue_Countup(b *testing.B) {
	var cnt Counter
	value.Store(cnt)
	b.ResetTimer()
	countup(incValue, b.N)
	cnt = value.Load().(Counter)
	b.Logf("%d -> %d", b.N, cnt)
}

実行結果

go test -bench .

  • atomic.Value が速い事は、いいとして Mutexatomic.AddInt64 より速いことが解せぬ
  • 何もしないとカウントアップの数合わないです(想定通り)他は大丈夫
$ go test -bench .
goos: linux
goarch: amd64
BenchmarkInc_Countup-4           	 2000000	       957 ns/op
--- BENCH: BenchmarkInc_Countup-4
    acounter_test.go:13: 1 -> 1
    acounter_test.go:13: 100 -> 100
    acounter_test.go:13: 10000 -> 9752
    acounter_test.go:13: 1000000 -> 982973
    acounter_test.go:13: 2000000 -> 1962072
BenchmarkLock_Countup-4          	 2000000	       936 ns/op
--- BENCH: BenchmarkLock_Countup-4
    acounter_test.go:20: 1 -> 1
    acounter_test.go:20: 100 -> 100
    acounter_test.go:20: 10000 -> 10000
    acounter_test.go:20: 1000000 -> 1000000
    acounter_test.go:20: 2000000 -> 2000000
BenchmarkAtomic_Countup-4        	 2000000	       943 ns/op
--- BENCH: BenchmarkAtomic_Countup-4
    acounter_test.go:27: 1 -> 1
    acounter_test.go:27: 100 -> 100
    acounter_test.go:27: 10000 -> 10000
    acounter_test.go:27: 1000000 -> 1000000
    acounter_test.go:27: 2000000 -> 2000000
BenchmarkAtomicValue_Countup-4   	 2000000	       904 ns/op
--- BENCH: BenchmarkAtomicValue_Countup-4
    acounter_test.go:36: 1 -> 1
    acounter_test.go:36: 100 -> 54
    acounter_test.go:36: 10000 -> 7125
    acounter_test.go:36: 1000000 -> 791697
    acounter_test.go:36: 2000000 -> 1586774
PASS

複数回の実行結果

複数回実行すれば・・・ atomic.AddInt 早くなるはずでは・・・

atomic.Value > Mutex > なにもしない > atomic.AddInt こ、これは・・・詳細なチェックしないとフラグでは・・・

$ for i in $(seq 1 3); do go test -bench . | grep 'ns/op'; done
BenchmarkInc_Countup-4           	 2000000	       998 ns/op
BenchmarkInc_Countup-4           	 2000000	       989 ns/op
BenchmarkInc_Countup-4           	 1000000	      1018 ns/op

BenchmarkLock_Countup-4          	 1000000	      1113 ns/op
BenchmarkLock_Countup-4          	 2000000	       986 ns/op
BenchmarkLock_Countup-4          	 1000000	      1311 ns/op

BenchmarkAtomic_Countup-4        	 1000000	      1010 ns/op
BenchmarkAtomic_Countup-4        	 2000000	      1130 ns/op
BenchmarkAtomic_Countup-4        	 1000000	      1051 ns/op

BenchmarkAtomicValue_Countup-4   	 2000000	      1013 ns/op
BenchmarkAtomicValue_Countup-4   	 2000000	       987 ns/op
BenchmarkAtomicValue_Countup-4   	 1000000	      1125 ns/op

Recap

  • 実装依存なら、コードを見て原因を探す
  • OS依存なら Profile とかしながら、ググったりして原因を探す
  • ハード依存なら・・・
  • ドキュメントに書いてあるとうれしいな

参考

1
0
1

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?