Skip to content

Instantly share code, notes, and snippets.

@alsritter
Created May 5, 2022 03:39
Show Gist options
  • Save alsritter/7d3b07bf2249f6f1fea890d99983627d to your computer and use it in GitHub Desktop.
Save alsritter/7d3b07bf2249f6f1fea890d99983627d to your computer and use it in GitHub Desktop.
测试并发 Map 性能
package main
import (
"fmt"
"sync"
"sync/atomic"
"testing"
)
type mapInterface interface {
Load(k interface{}) (v interface{}, ok bool)
Store(k, v interface{})
}
type MutexMap struct {
data map[interface{}]interface{}
mu sync.Mutex
}
func (m *MutexMap) Load(k interface{}) (v interface{}, ok bool) {
m.mu.Lock()
defer m.mu.Unlock()
v, ok = m.data[k]
return
}
func (m *MutexMap) Store(k, v interface{}) {
m.mu.Lock()
defer m.mu.Unlock()
m.data[k] = v
}
// RWMutexMap 是一个简单的 map + sync.RWMutex 的并发安全散列表实现
type RWMutexMap struct {
data map[interface{}]interface{}
mu sync.RWMutex
}
func (m *RWMutexMap) Load(k interface{}) (v interface{}, ok bool) {
m.mu.Lock()
defer m.mu.Unlock()
v, ok = m.data[k]
return
}
func (m *RWMutexMap) Store(k, v interface{}) {
m.mu.Lock()
defer m.mu.Unlock()
m.data[k] = v
}
func BenchmarkLoadStoreCollision(b *testing.B) {
ms := [...]mapInterface{
&MutexMap{data: map[interface{}]interface{}{}},
&RWMutexMap{data: map[interface{}]interface{}{}},
&sync.Map{},
}
// 测试对于同一个 key 的 n-1 并发读和 1 并发写的性能
for _, m := range ms {
b.Run(fmt.Sprintf("%T", m), func(b *testing.B) {
var i int64
b.RunParallel(func(pb *testing.PB) {
// 记录并发执行的 goroutine id
gid := int(atomic.AddInt64(&i, 1) - 1)
if gid == 0 {
// gid 为 0 的 goroutine 负责并发写
for i := 0; pb.Next(); i++ {
m.Store(0, i)
}
} else {
// gid 不为 0 的 goroutine 负责并发读
for pb.Next() {
m.Load(0)
}
}
})
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment