Skip to content

Instantly share code, notes, and snippets.

@spraints
Created April 12, 2024 15:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spraints/e3fa918add05fcacbeffea3371747c5a to your computer and use it in GitHub Desktop.
Save spraints/e3fa918add05fcacbeffea3371747c5a to your computer and use it in GitHub Desktop.
Mutex vs Atomics for read-heavy workload
/*
goos: darwin
goarch: amd64
pkg: github.com/github/gitrpcd/spraints/mutexvsatomic
cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
BenchmarkMutex-16 2182556 544.1 ns/op
--- BENCH: BenchmarkMutex-16
compare_test.go:71: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:71: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:71: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:71: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:71: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:71: maxes: [2 2 2 2 2 2 2 2 2 2]
BenchmarkRWMutex-16 2672090 480.0 ns/op
--- BENCH: BenchmarkRWMutex-16
compare_test.go:110: maxes: [2 1 2 2 2 2 2 2 2 2]
compare_test.go:110: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:110: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:110: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:110: maxes: [2 2 2 2 2 2 2 2 2 2]
BenchmarkAtomic-16 1000000000 0.5505 ns/op
--- BENCH: BenchmarkAtomic-16
compare_test.go:142: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:142: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:142: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:142: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:142: maxes: [2 2 2 2 2 2 2 2 2 2]
compare_test.go:142: maxes: [2 2 2 2 2 2 2 2 2 2]
PASS
ok github.com/github/gitrpcd/spraints/mutexvsatomic 5.309s
*/
package mutexvsatomic
import (
"sync"
"sync/atomic"
"testing"
)
func TestMutex(t *testing.T) {
testMutex(t, 1)
}
func BenchmarkMutex(b *testing.B) {
testMutex(b, b.N)
}
func TestRWMutex(t *testing.T) {
testRWMutex(t, 1)
}
func BenchmarkRWMutex(b *testing.B) {
testRWMutex(b, b.N)
}
func TestAtomic(t *testing.T) {
testAtomic(t, 1)
}
func BenchmarkAtomic(b *testing.B) {
testAtomic(b, b.N)
}
const workers = 10
func testMutex(t testing.TB, n int) {
var data struct {
value int32
lock sync.Mutex
}
data.value = 1
// Set up a bunch of readers.
maxSeen := make([]chan int32, 0, workers)
for i := 0; i < workers; i++ {
s := make(chan int32)
maxSeen = append(maxSeen, s)
go func() {
defer close(s)
var myMax int32 = -1
for j := 0; j < n; j++ {
data.lock.Lock()
if data.value > myMax {
myMax = data.value
}
data.lock.Unlock()
}
s <- myMax
}()
}
// Make a single write.
data.lock.Lock()
data.value += 1
data.lock.Unlock()
// Gather the results from the readers.
maxes := make([]int32, 0, workers)
for _, s := range maxSeen {
maxes = append(maxes, <-s)
}
t.Logf("maxes: %v", maxes)
}
func testRWMutex(t testing.TB, n int) {
var data struct {
value int32
lock sync.RWMutex
}
data.value = 1
// Set up a bunch of readers.
maxSeen := make([]chan int32, 0, workers)
for i := 0; i < workers; i++ {
s := make(chan int32)
maxSeen = append(maxSeen, s)
go func() {
defer close(s)
var myMax int32 = -1
for j := 0; j < n; j++ {
data.lock.RLock()
if data.value > myMax {
myMax = data.value
}
data.lock.RUnlock()
}
s <- myMax
}()
}
// Make a single write.
data.lock.Lock()
data.value += 1
data.lock.Unlock()
// Gather the results from the readers.
maxes := make([]int32, 0, workers)
for _, s := range maxSeen {
maxes = append(maxes, <-s)
}
t.Logf("maxes: %v", maxes)
}
func testAtomic(t testing.TB, n int) {
var value int32 = 1
// Set up a bunch of readers.
maxSeen := make([]chan int32, 0, workers)
for i := 0; i < workers; i++ {
s := make(chan int32)
maxSeen = append(maxSeen, s)
go func() {
defer close(s)
var myMax int32 = -1
for j := 0; j < n; j++ {
v := atomic.LoadInt32(&value)
if v > myMax {
myMax = v
}
}
s <- myMax
}()
}
// Make a single write.
atomic.AddInt32(&value, 1)
// Gather the results from the readers.
maxes := make([]int32, 0, workers)
for _, s := range maxSeen {
maxes = append(maxes, <-s)
}
t.Logf("maxes: %v", maxes)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment