concurrent_map

code:

基本信息

背景

标准库里的sync.Map,官方推荐两种场景适合:

The Map type is optimized for two common use cases: (1) when the entry for a given key is only ever written once but read many times, as in caches that only grow, or (2) when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.

其他的读写很重的,可能还是需要concurrent-map,基本原理就是分段锁,减少锁竞争的开销。

原理

核心逻辑是把map分片,配合读写锁,set的时候使用fnv32 hash算法找到对应的分片并存储,get的时候也是同样流程。减小锁的竞争。

新建map New,逻辑是新建32个分片的map。

var SHARD_COUNT = 32

// Creates a new concurrent map.
func New() ConcurrentMap {
    m := make(ConcurrentMap, SHARD_COUNT)
    for i := 0; i < SHARD_COUNT; i++ {
        m[i] = &ConcurrentMapShared{items: make(map[string]interface{})}
    }
    return m
}

设置值Set,逻辑是找到对应的分片map,上写锁并设置:

// Sets the given value under the specified key.
func (m ConcurrentMap) Set(key string, value interface{}) {
    // Get map shard.
    shard := m.GetShard(key)
    shard.Lock()
    shard.items[key] = value
    shard.Unlock()
}

取值,Get,逻辑是找到对应的分片map,上读锁并取值

// Get retrieves an element from map under given key.
func (m ConcurrentMap) Get(key string) (interface{}, bool) {
    // Get shard
    shard := m.GetShard(key)
    shard.RLock()
    // Get item from shard.
    val, ok := shard.items[key]
    shard.RUnlock()
    return val, ok
}