首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >[GO源码]并发安全 map [concurrent-map]

[GO源码]并发安全 map [concurrent-map]

原创
作者头像
Librant
修改2025-07-10 08:16:40
修改2025-07-10 08:16:40
1790
举报
文章被收录于专栏:跟我一起学 K8s跟我一起学 K8s

简介

并发安全 map,上一篇讲解了go 源码自带的 sync.Map{} 的源码实现;本篇文章主要是根据 github.com/orcaman/concurrent-map 中的代码实现,然后进行了相关代码的重构 github.com/libranwmq/cmap,后续需要使用并发安全 map 的童鞋,欢迎使用新的仓库,记得别忘了 star 一下。

这里说明下,为什么我想重构这个这个代码仓。这里的主要原因是,原仓库的代码基本不怎么维护了,我之前提的 issuse 也基本无人问津,并且通过这次重构,对于之前童鞋提出的问题,会在本仓库通过 PR 的方式进行迭代修复,这里也欢迎大家对新的仓库进行优化和问题修复,我会持续跟进本仓库相关问题进展。

源码解析

(这里只对 cmap 仓库的源码进行解析)

1 代码结构
  • 核心代码在 cmap.go 源码中
2 方法列表
代码语言:go
复制
type ConcurrentMapInterface[K Stringer, V any] interface {
	Count() int
	GetSlotNum() int
	IsEmpty() bool
	GetSlot(key K) *ConcurrentMapSlotted[K, V]
	Set(key K, value V)
	SetIfAbsent(key K, value V) bool
	MSet(data map[K]V)
	Upsert(key K, value V, cb UpsertCb[K, V]) V
	Get(key K) (V, bool)
	Pop(key K) (v V, ok bool)
	Has(key K) bool
	Remove(key K)
	RemoveCb(key K, cb RemoveCb[K, V]) bool
	Iter() <-chan Tuple[K, V]
	IterCb(key K, v V, cb IterCb[K, V])
	Items() map[K]V
	Keys() []K
	Tuples() []Tuple[K, V]
	Clear()
	UnmarshalJSON(b []byte) error
	MarshalJSON() ([]byte, error)
}
  • 这里就是并发 cmap 提供的方法列表;下面会进行逐一介绍;
  • Count() int:cmap 中 key 的数量
  • GetSlotNum() int:获取 slot 的大小,这个值在创建实例时指定,默认为 32,一旦指定后,将不支持修改;
  • IsEmpty() bool:判断是否是 空 的cmap
  • GetSlot(key K) *ConcurrentMapSlottedK, V:根据 key 值,返回当前 key 所在的 slot map;
  • Set(key K, value V):设置 cmap 值,如果key存在,则会覆盖旧值
  • SetIfAbsent(key K, value V) bool:对于 key 不存在,设置 value,返回是否成功设置;
  • MSet(data mapKV):批量设置值;
  • Upsert(key K, value V, cb UpsertCbK, V) V:根据 cb 函数返回的值,进行插入;
  • Pop(key K) (v V, ok bool):弹出 key,cmap 中的 key 会同步删除;
  • Has(key K) bool:判断 key 是否存在 cmap 中;
  • Remove(key K):删除一个 key
  • RemoveCb(key K, cb RemoveCbK, V) bool:根据 cb 函数返回值,进行删除;
  • Iter() <-chan TupleK, V:cmap 中的迭代器;
  • IterCb(key K, v V, cb IterCbK, V):根据 cb 函数值,进行迭代;
  • Items() mapKV:获取 cmap 中的所有 keyy/value;
  • Keys() []K:获取 key 的列表;
  • Tuples() []TupleK, V:获取所有 key/value 的键值对;
  • Clear():清理 cmap 中的 key;
  • UnmarshalJSON(b []byte) error:反序列化值,并将 key/value 设置到 cmap 中;
  • MarshalJSON() ([]byte, error):对 cmap 中的 key/value 进行序列化;
3 结构讲解
代码语言:go
复制
type SlotingFunc[K Stringer] func(key K) uint32

type concurrentMap[K Stringer, V any] struct {
	_       nocopy.NoCopy
	slotNum int
	sloting SlotingFunc[K]
	slots   []*ConcurrentMapSlotted[K, V]
}

concurrentMap:实际并发存储的 map 结构体

  • slotNum: map 分片大小
  • sloting:分片函数,什么 key 放在哪个 slot 里
  • slots:map 的分片存储
代码语言:go
复制
type ConcurrentMapSlotted[K Stringer, V any] struct {
	items map[K]V
	sync.RWMutex
}
  • items:每个分片中存储的 key/value
  • sync.RWMutex:读写锁

创建 concurrentMap 实例:

代码语言:go
复制
New[K Stringer, V any](opts ...ConcurrentMapOption[K, V]) ConcurrentMapInterface[K, V]
  • 这里使用了泛型来生成 concurrentMap 的实例,对于任何实现了 Stringer 接口的类型,都可以作为 cmap 中的 key
代码语言:go
复制
type Stringer interface {
	fmt.Stringer
	comparable
}
  • Stringer 接口:实现 fmt.Stringer 中的方法
代码语言:go
复制
String() string {}
  • cmap 中默认实现了三种类型
代码语言:go
复制
type String string
type Integer int
type Integer32 int32
  • 如果需要支持自定义类型作为 cmap 中的 key,只需要实现 String() string {} 方法即可;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 源码解析
    • 1 代码结构
    • 2 方法列表
    • 3 结构讲解
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档