package
2.0.0+incompatible
Repository: https://github.com/solaa51/swagger.git
Documentation: pkg.go.dev

# README

key value map高并发读写库

当前性能不如官方syncMap 推荐使用官方库

咱这库 现在性能虽然不咋的 但是可做些扩展 实现部分redis的功能
后面再把map替换为链表,性能上提升下
使用循环链表重写 : 循环链表适用于需要频繁插入、删除和修改数据集合的场景
    1. key必须为 comparable 
    2. 得有自动扩容 不够时 自动扩充10个元数据
    3. 得有自动回收空间 超过2/3无效时触发
    4. 外层记录 data总数[包含删除] 有效data数[不包含删除] 当前容量
    5. 数据得有标记删除
    6. 利用atomic.Pointer来操作数据指针
    7. 先搞一个循环链表试试水
    8. 然后尝试atomic操作
    9. 最后整合进当前库

^uintptr(0) == -1

各种并发kv库使用场景比较 - 线程安全

1. 官方syncMap 多读少写 [利用map可快速定位]
2. 

目标使用场景:

1. 需要频繁读写
2. 分片数为cpu核数的倍数
3. 数据量较大

使用示例

不分片 少量数据使用

package main
func main() {
	iKv := kvLibrary.NewKVMap[int, int](0)
	iKv.Set(1, 1)
	fmt.Println(iKv.Get(1))
}

分片调用

package main

//自定义string类型 实现String方法
type tStr string
func (t tStr) String() string {
	return string(t)
}

func main() {
	kv := kvLibrary.NewShardKV[tStr, int](0, 0)
	kv.Set("1", 1)

	fmt.Println(kv.Get("1"))
}
//并发测试
package main
func main() {
    iKv := kvLibrary.NewShardKV[tStr, int](1, 0)

	testK := tStr("test")
	allNum := 10000

	var wg sync.WaitGroup
	wg.Add(allNum)
	for i := range allNum {
		go func(i int) {
			if i%3 == 0 {
				iKv.Set(testK, i)
			}

			if i%3 == 1 {
				iKv.Get(testK)
			}

			if i%3 == 2 {
				iKv.Del(testK)
			}

			wg.Done()
		}(i)
	}
	wg.Wait()
}

// key需要实现String()方法
type tStr string

func (t tStr) String() string {
	return string(t)
}

https://github.com/alphadose/haxmap 这个库将性能做到了极致

只读模式下的性能比较

goos: darwin
goarch: amd64
pkg: github.com/solaa51/swagger/library/kvLibrary
cpu: Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
BenchmarkGoSyncMapReadsOnly-12             55284             22057 ns/op               0 B/op          0 allocs/op
BenchmarkAtomicShardMapReadsOnly-12        13494             90002 ns/op           15265 B/op       3996 allocs/op
BenchmarkAtomicMapReadsOnly-12               640           1941287 ns/op               1 B/op          0 allocs/op
BenchmarkAtomic-12                           577           2023132 ns/op               4 B/op          0 allocs/op
BenchmarkMutexMap-12                        4221            277431 ns/op               1 B/op          0 allocs/op
--- FAIL: BenchmarkSyncMap
FAIL
exit status 1
FAIL    github.com/solaa51/swagger/library/kvLibrary    7.587s

单纯读取数据的性能比较: go原生syncMap 性能:20885 ns/op 0 B/op 0 allocs/op 自己的分片KV [cpu核数*2] 性能:90002 ns/op 15265 B/op 3996 allocs/op 分片数推荐为cpu核数的2数递增 倍数微增 读取性能提升明显,但不会超过 syncMap 自己不分配KV 1941287 ns/op 1 B/op 0 allocs/op 原生map+sync.Mutex 性能最差:277431 ns/op 1 B/op 0 allocs/op

1:1读写下的性能差异

goos: darwin
goarch: amd64
pkg: github.com/solaa51/swagger/library/kvLibrary
cpu: Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
BenchmarkGoSyncMapReadsOnly-12              7389            163160 ns/op          127060 B/op      11777 allocs/op
BenchmarkAtomicShardMapReadsOnly-12         5778            228887 ns/op           31210 B/op       7992 allocs/op
BenchmarkAtomicMapReadsOnly-12               229           5062992 ns/op             722 B/op          0 allocs/op
BenchmarkAtomic-12                           264           4747591 ns/op            1309 B/op          0 allocs/op
BenchmarkMutexMap-12                        1852            664912 ns/op             189 B/op          0 allocs/op
--- FAIL: BenchmarkSyncMap
FAIL
exit status 1
FAIL    github.com/solaa51/swagger/library/kvLibrary    8.115s

貌似map本身的性能 已经限制了读写性能

不管我这个怎么弄,本质还是map 

若要继续提升,就得用链表 + 原子操作

使用链表 查找元素就是个关键问题了

int类型的hash值就是他自己的 无符号类型返回

如果不将分片对外,采用内部计数,这样就可以不需要hash计算
    或者保留分片可允许外部扩展
    内部采用计数法写入数据
    干掉hash key只需限定为 基础类型和指针就可以了
    我草 查找时 没有hash又搞不定哪个分组了

不能再使用map 将key和value都放到struct下。利用空间换时间