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

## 所感

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

## 概要

```go
var num int64
num++
```

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

- 何もせずに `num++`
- `mutex.Loc() num++ mutex.Unlock()`
- `atomic.AddInt64`
- `atomic.Value` の `Load(), Store()`

## コード

### カウントアップ

```go: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()
}
```

### ベンチマーク

```go: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` が速い事は、いいとして `Mutex` が `atomic.AddInt64` より速いことが解せぬ
- 何もしないとカウントアップの数合わないです（想定通り）他は大丈夫

```bash
$ 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` こ、これは・・・詳細なチェックしないとフラグでは・・・


```bash
$ 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 とかしながら、ググったりして原因を探す
- ハード依存なら・・・
- ドキュメントに書いてあるとうれしいな

## 参考

- [atomicパッケージが必要な理由と使い方](https://qiita.com/lufia/items/35f6f1e324c09610806a)
- [go標準のbenchmark機能の使い方](https://qiita.com/marnie_ms4/items/7014563083ca1d824905)