新手问题 并发map或者类似的结构

codinghxl · 2017年12月18日 · 最后由 SaltySailor 回复于 2017年12月20日 · 507 次阅读

请问我目前有这么一个需求: map[string] item{ key1:value1, key2:value2, key3:value3 } 这么一个数据结构,目前存在多个线程更新数据,多个线程读取数据,但是针对同一个 key 的数据,只会同时存在一个线程更新,多个线程读取的情况。

请问目前有方便高效的解决方案吗? 类似 java ConcurrentHashMap 的 go 实现有么?

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio

Go 1.9 sync.Map

据说 Go 1.9 sync.Map 性能比自己用 sync.Metux map 好

1.9 的 sync.Map 也是有全局锁的,如果想作为内存数据库用,还是自己实现吧。 concurrent-map的实现与 Java 中 concurrentHashMap 类似,用多把锁,锁对应的桶。这种方式主要是注意 key 的均匀分布。 concurrent-map 是用 fnv32 处理 string 类型的 key。不过实际上的 key 经常是 id,可以直接简单地取余来确定放哪个桶

type CMap struct {
    slotCnt int64
    buckets []map[int64]interface{}
    locks   []*sync.RWMutex
}

func (m *CMap) Init(cnt uint8) {
    if cnt == 0 {
        cnt = 1
    }
    m.slotCnt = int64(cnt)
    // 初始化m.buckets
    // 初始化m.locks  
}

func (m *CMap) Set(key int64, v interface{}) {
    if m.slotCnt == 0 {
        m.Init(1)
    }
    slot := key % m.slotCnt
    l := m.locks[slot]
    l.Lock()
    m.buckets[slot][key] = v
    l.Unlock()
}
  • map 中 key 的数量不经常变更时,不 add/delete key,只变更 value,sync.Map效率优于concurrent-map
  • 如果存在大量 key 数量变更时,经常 add/delete key,concurrent-map优于sync.Map

golang 没有完善的 concurrent map 实现,开源版是一个固定的并发度 (无选项)

建议参考 java,修改一个自己的版本

我大概想到两个点: 1.关于 map 这类数据结构如果用锁的话考虑给数据分片,分成若干个片然后给每个片配一把锁,细化一下锁的颗粒度,有效减少冲突。 2.针对你这种 “只会同时存在一个线程更新,多个线程读取的情况” 也就是读多写少的情景,考虑用 copy-on-write 优化,具体含义可以 google 一下。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册