Skip to content

Instantly share code, notes, and snippets.

@zz-jason
Created April 4, 2023 13:53
Show Gist options
  • Save zz-jason/4a74a7e650625b74ba30a1ff80d565f8 to your computer and use it in GitHub Desktop.
Save zz-jason/4a74a7e650625b74ba30a1ff80d565f8 to your computer and use it in GitHub Desktop.
package main
import (
"math/rand"
"sync"
"sync/atomic"
"testing"
"time"
)
type OptimisticSpinStruct[T any] struct {
OptimisticLatch atomic.Uint64
CurrentValue T
}
func (o *OptimisticSpinStruct[T]) Get() (T, uint64) {
for {
latch := o.OptimisticLatch.Load()
// ensure don't read during writing
for latch&1 == 1 {
latch = o.OptimisticLatch.Load()
}
value := o.CurrentValue
if latch == o.OptimisticLatch.Load() {
return value, latch
}
}
}
func (o *OptimisticSpinStruct[T]) Set(value T) {
o.OptimisticLatch.Store(o.OptimisticLatch.Load() + 1)
o.CurrentValue = value
o.OptimisticLatch.Store(o.OptimisticLatch.Load() + 1)
}
type PessimisticSpinStructV2[T any] struct {
OptimisticLatch atomic.Uint64
CurrentValue T
}
type PessimisticSpinStruct[T any] struct {
PessimisticLatch sync.RWMutex
CurrentValue T
}
func (p *PessimisticSpinStruct[T]) Get() T {
p.PessimisticLatch.RLock()
defer p.PessimisticLatch.RUnlock()
return p.CurrentValue
}
func (p *PessimisticSpinStruct[T]) Set(value T) {
p.PessimisticLatch.Lock()
defer p.PessimisticLatch.Unlock()
p.CurrentValue = value
}
func BenchmarkOptimisticSpinStructGet(b *testing.B) {
var o OptimisticSpinStruct[int]
for i := 0; i < b.N; i++ {
o.Get()
}
}
func BenchmarkOptimisticSpinStructSet(b *testing.B) {
var o OptimisticSpinStruct[int]
for i := 0; i < b.N; i++ {
o.Set(i)
}
}
func BenchmarkOptimisticSpinStructSetConcurrently(b *testing.B) {
var o OptimisticSpinStruct[int]
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
o.Set(0)
}
})
}
func BenchmarkOptimisticSpinStructGetConcurrently(b *testing.B) {
var o OptimisticSpinStruct[int]
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
o.Get()
}
})
}
func BenchmarkOptimisticSpinStructGetSetConcurrently(b *testing.B) {
var o OptimisticSpinStruct[int]
rand.Seed(time.Now().Unix())
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if rand.Intn(1000) == 0 {
o.Set(0)
} else {
o.Get()
}
}
})
}
func BenchmarkPessimisticSpinStructGet(b *testing.B) {
var p PessimisticSpinStruct[int]
for i := 0; i < b.N; i++ {
p.Get()
}
}
func BenchmarkPessimisticSpinStructGetConcurrently(b *testing.B) {
var p PessimisticSpinStruct[int]
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
p.Get()
}
})
}
func BenchmarkPessimisticSpinStructSet(b *testing.B) {
var p PessimisticSpinStruct[int]
for i := 0; i < b.N; i++ {
p.Set(i)
}
}
func BenchmarkPessimisticSpinStructSetConcurrently(b *testing.B) {
var p PessimisticSpinStruct[int]
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
p.Set(0)
}
})
}
func BenchmarkPessimisticSpinStructGetSetConcurrently(b *testing.B) {
var p PessimisticSpinStruct[int]
rand.Seed(time.Now().Unix())
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if rand.Intn(1000) == 0 {
p.Set(0)
} else {
p.Get()
}
}
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment