github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/core/container/map_test.go (about) 1 package container 2 3 import ( 4 "github.com/nyan233/littlerpc/core/utils/random" 5 "strconv" 6 "testing" 7 "time" 8 ) 9 10 type MapOnTest[Key any, Value any] interface { 11 LoadOk(Key) (Value, bool) 12 Store(Key, Value) 13 Delete(Key) 14 Len() int 15 } 16 17 func TestAllMap(t *testing.T) { 18 type RCUMapStore[Key comparable, Val any] interface { 19 StoreMulti(kvs []RCUMapElement[Key, Val]) 20 } 21 printTestMap := func(printFn func(args ...any), iMap MapOnTest[string, int], errStr string) { 22 switch iMap.(type) { 23 case *MutexMap[string, int]: 24 printFn("MutexMap : ", errStr) 25 case *RWMutexMap[string, int]: 26 printFn("RWMutexMap : ", errStr) 27 case *SliceMap[string, int]: 28 printFn("SliceMap : ", errStr) 29 case *SyncMap118[string, int]: 30 printFn("SyncMap118 : ", errStr) 31 case *RCUMap[string, int]: 32 printFn("RCUMap : ", errStr) 33 } 34 } 35 type gen struct { 36 Key string 37 Value int 38 } 39 const KeyNum int = 16384 40 for i := 0; i < 5; i++ { 41 var iMap MapOnTest[string, int] 42 switch i { 43 case 0: 44 iMap = &MutexMap[string, int]{} 45 case 1: 46 iMap = &RWMutexMap[string, int]{} 47 case 2: 48 iMap = NewSliceMap[string, int](8) 49 case 3: 50 iMap = &SyncMap118[string, int]{} 51 case 4: 52 iMap = NewRCUMap[string, int](128) 53 } 54 genData := make([]gen, KeyNum) 55 now := time.Now() 56 for j := 0; j < KeyNum; j++ { 57 genData[j] = gen{ 58 Key: strconv.FormatInt(int64((1<<16)+j), 16), 59 Value: j + 1, 60 } 61 if _, ok := iMap.(RCUMapStore[string, int]); !ok { 62 iMap.Store(genData[j].Key, genData[j].Value) 63 } 64 } 65 if inter, ok := iMap.(RCUMapStore[string, int]); ok { 66 kvs := make([]RCUMapElement[string, int], len(genData)) 67 for k, v := range genData { 68 kvs[k] = RCUMapElement[string, int]{ 69 Key: v.Key, 70 Value: v.Value, 71 } 72 } 73 inter.StoreMulti(kvs) 74 } 75 // 插入一个已经存在的键, 检查长度是否计算正确 76 oldLen := iMap.Len() 77 iMap.Store(genData[KeyNum/2].Key, genData[KeyNum/2].Value) 78 if oldLen != iMap.Len() { 79 printTestMap(t.Fatal, iMap, "store after length not equal") 80 } 81 // 删除一个不存在的键, 检查长度计算是否正确 82 oldLen = iMap.Len() 83 iMap.Delete(random.GenStringOnAscii(100)) 84 if oldLen != iMap.Len() { 85 printTestMap(t.Fatal, iMap, "delete after length not equal") 86 } 87 // 插入一个使用初始化数据的键, 检查长度 88 oldLen = iMap.Len() 89 iMap.Store("", 0) 90 if iMap.Len() != oldLen+1 { 91 printTestMap(t.Fatal, iMap, "store init key after length not equal") 92 } 93 iMap.Delete("") 94 if iMap.Len() != oldLen { 95 printTestMap(t.Fatal, iMap, "delete init key after length not equal") 96 } 97 for k, v := range genData { 98 genV, ok := iMap.LoadOk(v.Key) 99 if genV != k+1 { 100 printTestMap(t.Fatal, iMap, "genData.Value not equal") 101 } 102 if !ok { 103 printTestMap(t.Fatal, iMap, "genData.Key not found") 104 } 105 iMap.Delete(v.Key) 106 } 107 if iMap.Len() != 0 { 108 printTestMap(t.Fatal, iMap, "MaperOnTest length a not equal zero") 109 } 110 printTestMap(t.Log, iMap, "ExecTime :"+time.Since(now).String()) 111 } 112 } 113 114 func BenchmarkGenericsMap(b *testing.B) { 115 mu := MutexMap[string, int]{} 116 rwMu := RWMutexMap[string, int]{} 117 writeTime := 100 * time.Nanosecond 118 sMap := NewSliceMap[string, int](100) 119 b.Run("SliceMap", func(b *testing.B) { 120 b.ReportAllocs() 121 for i := 0; i < b.N; i++ { 122 sMap.Store(strconv.Itoa(i%100), i) 123 } 124 }) 125 b.Run("MutexBackgroundWrite", func(b *testing.B) { 126 go func() { 127 for { 128 time.Sleep(writeTime) 129 mu.Store("hash", 1) 130 } 131 }() 132 b.ReportAllocs() 133 for i := 0; i < b.N; i++ { 134 mu.Load("hash") 135 } 136 }) 137 b.Run("RWMutexBackgroundWrite", func(b *testing.B) { 138 go func() { 139 for { 140 time.Sleep(writeTime) 141 rwMu.Store("hash", 1) 142 } 143 }() 144 b.ReportAllocs() 145 for i := 0; i < b.N; i++ { 146 rwMu.Load("hash") 147 } 148 }) 149 }