Skip to content

Commit 625f807

Browse files
authored
Cmap (#5)
* 分区map * 更新
1 parent 2c3b87b commit 625f807

File tree

10 files changed

+460
-12
lines changed

10 files changed

+460
-12
lines changed

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ rwmap与sync.Map类似支持并发访问,只解决sync.Map 2个问题.
160160
1. 没有Len成员函数
161161
2. 以及没有使用泛型语法,有运行才发现类型使用错误的烦恼
162162
```go
163-
var m RWMap[string, string] // 声明一个string, string的map
163+
var m rwmap.RWMap[string, string] // 声明一个string, string的map
164164
m.Store("hello", "1") // 保存
165165
v1, ok1 := m.Load("hello") // 获取值
166166
v1, ok1 = m.LoadAndDelete("hello") //返回hello对应值,然后删除hello
@@ -182,3 +182,28 @@ m.Len()// 获取长度
182182
allKeys := m.Keys() //返回所有的key
183183
allValues := m.Values()// 返回所有的value
184184
```
185+
## 十二、`cmap`
186+
cmap是用锁分区的方式实现的,(TODO与sync.Map测试下性能对比,从sync.Map的源代码上看只能用于读多写少,如果写读对半分,或者写多读少?)
187+
```go
188+
var m cmap.CMap[string, string] // 声明一个string, string的map
189+
m.Store("hello", "1") // 保存
190+
v1, ok1 := m.Load("hello") // 获取值
191+
v1, ok1 = m.LoadAndDelete("hello") //返回hello对应值,然后删除hello
192+
Delete("hello") // 删除
193+
v1, ok1 = m.LoadOrStore("hello", "world")
194+
195+
// 遍历,使用回调函数
196+
m.Range(func(key, val string) bool {
197+
fmt.Printf("k:%s, val:%s\n"i, key, val)
198+
return true
199+
})
200+
201+
// 遍历,迭代器
202+
for pair := range m.Iter() {
203+
fmt.Printf("k:%s, val:%s\n", pair.Key, pair.Val)
204+
}
205+
206+
m.Len()// 获取长度
207+
allKeys := m.Keys() //返回所有的key
208+
allValues := m.Values()// 返回所有的value
209+
```

api/api.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,12 @@ type Trie[V any] interface {
3838
Delete(k string)
3939
Len() int
4040
}
41+
42+
type CMaper[K comparable, V any] interface {
43+
Delete(key K)
44+
Load(key K) (value V, ok bool)
45+
LoadAndDelete(key K) (value V, loaded bool)
46+
LoadOrStore(key K, value V) (actual V, loaded bool)
47+
Range(f func(key K, value V) bool)
48+
Store(key K, value V)
49+
}

btree/btree.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
var _ api.SortedMap[int, int] = (*Btree[int, int])(nil)
1818
var ErrNotFound = errors.New("btree not found")
1919

20-
//btree头结点
20+
// btree头结点
2121
type Btree[K constraints.Ordered, V any] struct {
2222
count int //当前元素个数
2323
root *node[K, V] // root结点指针

cmap/cmap.go

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
package cmap
2+
3+
import (
4+
"reflect"
5+
"runtime"
6+
"sync"
7+
"unsafe"
8+
9+
"github.com/antlabs/gstl/api"
10+
"github.com/antlabs/gstl/mapex"
11+
xxhash "github.com/cespare/xxhash/v2"
12+
)
13+
14+
var _ api.CMaper[int, int] = (*CMap[int, int])(nil)
15+
16+
type Pair[K comparable, V any] struct {
17+
Key K
18+
Val V
19+
}
20+
21+
type CMap[K comparable, V any] struct {
22+
bucket []Item[K, V]
23+
keySize int
24+
isKeyStr bool
25+
}
26+
27+
type Item[K comparable, V any] struct {
28+
rw sync.RWMutex
29+
m map[K]V
30+
}
31+
32+
func New[K comparable, V any]() (c *CMap[K, V]) {
33+
np := runtime.GOMAXPROCS(0)
34+
if np <= 0 {
35+
np = 8
36+
}
37+
38+
c = &CMap[K, V]{
39+
bucket: make([]Item[K, V], np),
40+
}
41+
42+
for i := range c.bucket {
43+
c.bucket[i].m = make(map[K]V)
44+
}
45+
return c
46+
}
47+
48+
// 计算hash值
49+
func (c *CMap[K, V]) calHash(k K) uint64 {
50+
var key string
51+
52+
if c.isKeyStr {
53+
// 直接赋值会报错, 使用unsafe绕过编译器检查
54+
key = *(*string)(unsafe.Pointer(&k))
55+
} else {
56+
// 因为xxhash.Sum64String 接收string, 所以要把非string类型变量当成string类型来处理
57+
key = *(*string)(unsafe.Pointer(&reflect.StringHeader{
58+
Data: uintptr(unsafe.Pointer(&k)),
59+
Len: c.keySize,
60+
}))
61+
}
62+
63+
return xxhash.Sum64String(key)
64+
}
65+
66+
// 保存key的类型和key的长度
67+
func (h *CMap[K, V]) keyTypeAndKeySize() {
68+
var k K
69+
switch (interface{})(k).(type) {
70+
case string:
71+
h.isKeyStr = true
72+
default:
73+
h.keySize = int(unsafe.Sizeof(k))
74+
}
75+
}
76+
77+
// 找到索引
78+
func (c *CMap[K, V]) findIndex(key K) *Item[K, V] {
79+
index := c.calHash(key) % uint64(len(c.bucket))
80+
return &c.bucket[index]
81+
}
82+
83+
// 删除
84+
func (c *CMap[K, V]) Delete(key K) {
85+
item := c.findIndex(key)
86+
item.rw.Lock()
87+
delete(item.m, key)
88+
item.rw.Unlock()
89+
}
90+
91+
func (c *CMap[K, V]) Load(key K) (value V, ok bool) {
92+
item := c.findIndex(key)
93+
item.rw.RLock()
94+
value, ok = item.m[key]
95+
item.rw.RUnlock()
96+
return
97+
}
98+
99+
func (c *CMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
100+
item := c.findIndex(key)
101+
item.rw.Lock()
102+
value, loaded = item.m[key]
103+
if !loaded {
104+
item.rw.Unlock()
105+
return
106+
}
107+
delete(item.m, key)
108+
item.rw.Unlock()
109+
return
110+
}
111+
112+
func (c *CMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
113+
item := c.findIndex(key)
114+
item.rw.Lock()
115+
actual, loaded = item.m[key]
116+
if !loaded {
117+
actual = value
118+
item.m[key] = actual
119+
item.rw.Unlock()
120+
return
121+
}
122+
actual, loaded = item.m[key]
123+
item.rw.Unlock()
124+
return
125+
}
126+
127+
func (c *CMap[K, V]) Range(f func(key K, value V) bool) {
128+
for i := 0; i < len(c.bucket); i++ {
129+
item := &c.bucket[i]
130+
item.rw.RLock()
131+
for k, v := range item.m {
132+
if !f(k, v) {
133+
item.rw.RUnlock()
134+
return
135+
}
136+
}
137+
item.rw.RUnlock()
138+
}
139+
}
140+
141+
func (c *CMap[K, V]) Iter() (rv chan Pair[K, V]) {
142+
143+
rv = make(chan Pair[K, V])
144+
var wg sync.WaitGroup
145+
146+
wg.Add(len(c.bucket))
147+
148+
go func() {
149+
wg.Wait()
150+
close(rv)
151+
}()
152+
153+
for i := 0; i < len(c.bucket); i++ {
154+
item := &c.bucket[i]
155+
go func(item *Item[K, V]) {
156+
157+
defer wg.Done()
158+
item.rw.RLock()
159+
for k, v := range item.m {
160+
rv <- Pair[K, V]{Key: k, Val: v}
161+
}
162+
item.rw.RUnlock()
163+
164+
}(item)
165+
}
166+
return rv
167+
168+
}
169+
170+
func (c *CMap[K, V]) Store(key K, value V) {
171+
item := c.findIndex(key)
172+
item.rw.Lock()
173+
item.m[key] = value
174+
item.rw.Unlock()
175+
return
176+
}
177+
178+
// TODO 优化
179+
func (c *CMap[K, V]) Keys() []K {
180+
l := c.Len()
181+
all := make([]K, 0, l)
182+
if l == 0 {
183+
return nil
184+
}
185+
186+
for i := 0; i < len(c.bucket); i++ {
187+
188+
item := &c.bucket[i]
189+
item.rw.RLock()
190+
all = append(all, mapex.Keys(item.m)...)
191+
item.rw.RUnlock()
192+
}
193+
return all
194+
}
195+
196+
func (c *CMap[K, V]) Values() []V {
197+
l := c.Len()
198+
all := make([]V, 0, l)
199+
if l == 0 {
200+
return nil
201+
}
202+
203+
for i := 0; i < len(c.bucket); i++ {
204+
205+
item := &c.bucket[i]
206+
item.rw.RLock()
207+
all = append(all, mapex.Values(item.m)...)
208+
item.rw.RUnlock()
209+
}
210+
return all
211+
}
212+
213+
func (c *CMap[K, V]) Len() int {
214+
l := 0
215+
for i := 0; i < len(c.bucket); i++ {
216+
item := &c.bucket[i]
217+
item.rw.RLock()
218+
l += len(item.m)
219+
item.rw.RUnlock()
220+
}
221+
return l
222+
}

0 commit comments

Comments
 (0)