分片锁 Map
难度:⭐⭐⭐ 困难
考点
- 降低锁粒度提高并发性能
- hash 分片策略
- 与单锁 map 的性能对比
题目描述
实现一个分片锁 Map(ShardedMap),通过将数据分散到多个分片(每个分片独立加锁)来减少锁竞争。
要求:
- 固定 16 个分片
- 用 key 的 hash 决定分片
- 支持 Set、Get、Delete、Len 操作
- 并发安全
函数签名
go
type ShardedMap struct { ... }
func NewShardedMap() *ShardedMap
func (m *ShardedMap) Set(key string, value interface{})
func (m *ShardedMap) Get(key string) (interface{}, bool)
func (m *ShardedMap) Delete(key string)
func (m *ShardedMap) Len() int提示
- 16 个 shard,每个 shard 有自己的 sync.RWMutex + map
- hash 函数可以用 fnv32:
hash/fnv包 - 分片索引 = hash(key) % numShards
- Len() 需要遍历所有分片加锁求和
参考答案(Go)
点击展开参考答案
go
//go:build ignore
package answer
import (
"hash/fnv"
"sync"
)
const numShards = 16
type shard struct {
mu sync.RWMutex
data map[string]interface{}
}
type ShardedMap struct {
shards [numShards]*shard
}
func NewShardedMap() *ShardedMap {
m := &ShardedMap{}
for i := range m.shards {
m.shards[i] = &shard{data: make(map[string]interface{})}
}
return m
}
func (m *ShardedMap) getShard(key string) *shard {
h := fnv.New32a()
h.Write([]byte(key))
return m.shards[h.Sum32()%numShards]
}
func (m *ShardedMap) Set(key string, value interface{}) {
s := m.getShard(key)
s.mu.Lock()
s.data[key] = value
s.mu.Unlock()
}
func (m *ShardedMap) Get(key string) (interface{}, bool) {
s := m.getShard(key)
s.mu.RLock()
v, ok := s.data[key]
s.mu.RUnlock()
return v, ok
}
func (m *ShardedMap) Delete(key string) {
s := m.getShard(key)
s.mu.Lock()
delete(s.data, key)
s.mu.Unlock()
}
func (m *ShardedMap) Len() int {
total := 0
for _, s := range m.shards {
s.mu.RLock()
total += len(s.data)
s.mu.RUnlock()
}
return total
}