kvLibrary

package
v1.1.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2024 License: Apache-2.0 Imports: 5 Imported by: 0

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下。利用空间换时间

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type KVMap

type KVMap[K comparable, V any] struct {
	// contains filtered or unexported fields
}

func NewKVMap

func NewKVMap[K comparable, V any](cap int) *KVMap[K, V]

func (*KVMap[K, V]) Clear

func (m *KVMap[K, V]) Clear()

func (*KVMap[K, V]) Del

func (m *KVMap[K, V]) Del(k K)

func (*KVMap[K, V]) Get

func (m *KVMap[K, V]) Get(k K) (V, bool)

func (*KVMap[K, V]) Items

func (m *KVMap[K, V]) Items() map[K]V

Items 获取所有数据 复制后返回

func (*KVMap[K, V]) Len

func (m *KVMap[K, V]) Len() int

func (*KVMap[K, V]) Set

func (m *KVMap[K, V]) Set(k K, v V)

func (*KVMap[K, V]) SetOnce

func (m *KVMap[K, V]) SetOnce(k K, v V) bool

SetOnce 仅允许单次写入

type ShardKV

type ShardKV[K ShardKey, V any] struct {
	// contains filtered or unexported fields
}

func NewShardKV

func NewShardKV[K ShardKey, V any](shardNum int, perCap int) *ShardKV[K, V]

NewShardKV 创建分片kv shardNum 分片数 perCap 每个分片容量

func (*ShardKV[K, V]) Clear

func (s *ShardKV[K, V]) Clear()

func (*ShardKV[K, V]) Del

func (s *ShardKV[K, V]) Del(key K)

func (*ShardKV[K, V]) Get

func (s *ShardKV[K, V]) Get(key K) (V, bool)

func (*ShardKV[K, V]) Items

func (s *ShardKV[K, V]) Items() map[K]V

func (*ShardKV[K, V]) Len

func (s *ShardKV[K, V]) Len() int

func (*ShardKV[K, V]) Set

func (s *ShardKV[K, V]) Set(key K, value V)

type ShardKey

type ShardKey interface {
	String() string
	comparable
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL