github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/collection/skipmap/readme.md (about) 1 <p align="center"> 2 <img src="https://raw.githubusercontent.com/zhangyunhao116/public-data/master/skipmap-logo.png"/> 3 </p> 4 5 ## Introduction 6 7 skipmap is a high-performance concurrent map based on skip list. In typical pattern(one million operations, 90%LOAD 9%STORE 1%DELETE), the skipmap up to 3x ~ 10x faster than the built-in sync.Map. 8 9 The main idea behind the skipmap is [A Simple Optimistic Skiplist Algorithm](<https://people.csail.mit.edu/shanir/publications/LazySkipList.pdf>). 10 11 Different from the sync.Map, the items in the skipmap are always sorted, and the `Load` and `Range` operations are wait-free (A goroutine is guaranteed to complete a operation as long as it keeps taking steps, regardless of the activity of other goroutines). 12 13 14 15 ## Features 16 17 - Concurrent safe API with high-performance. 18 - Wait-free Load and Range operations. 19 - Sorted items. 20 21 22 23 ## When should you use skipmap 24 25 In these situations, `skipmap` is better 26 27 - **Sorted elements is needed**. 28 - **Concurrent calls multiple operations**. such as use both `Load` and `Store` at the same time. 29 30 In these situations, `sync.Map` is better 31 32 - Only one goroutine access the map for most of the time, such as insert a batch of elements and then use only `Load` (use built-in map is even better). 33 34 35 36 ## QuickStart 37 38 ```go 39 package main 40 41 import ( 42 "fmt" 43 44 "github.com/bytedance/gopkg/collection/skipmap" 45 ) 46 47 func main() { 48 l := skipmap.NewInt() 49 50 for _, v := range []int{10, 12, 15} { 51 l.Store(v, v+100) 52 } 53 54 v, ok := l.Load(10) 55 if ok { 56 fmt.Println("skipmap load 10 with value ", v) 57 } 58 59 l.Range(func(key int, value interface{}) bool { 60 fmt.Println("skipmap range found ", key, value) 61 return true 62 }) 63 64 l.Delete(15) 65 fmt.Printf("skipmap contains %d items\r\n", l.Len()) 66 } 67 68 ``` 69 70 71 72 ## Benchmark 73 74 Go version: go1.16.2 linux/amd64 75 76 CPU: AMD 3700x(8C16T), running at 3.6GHz 77 78 OS: ubuntu 18.04 79 80 MEMORY: 16G x 2 (3200MHz) 81 82 ![benchmark](https://raw.githubusercontent.com/zhangyunhao116/public-data/master/skipmap-benchmark.png) 83 84 ```shell 85 $ go test -run=NOTEST -bench=. -benchtime=100000x -benchmem -count=20 -timeout=60m > x.txt 86 $ benchstat x.txt 87 ``` 88 89 ``` 90 name time/op 91 Int64/Store/skipmap-16 158ns ±12% 92 Int64/Store/sync.Map-16 700ns ± 4% 93 Int64/Load50Hits/skipmap-16 10.1ns ±14% 94 Int64/Load50Hits/sync.Map-16 14.8ns ±23% 95 Int64/30Store70Load/skipmap-16 50.6ns ±20% 96 Int64/30Store70Load/sync.Map-16 592ns ± 7% 97 Int64/1Delete9Store90Load/skipmap-16 27.5ns ±13% 98 Int64/1Delete9Store90Load/sync.Map-16 480ns ± 4% 99 Int64/1Range9Delete90Store900Load/skipmap-16 34.2ns ±26% 100 Int64/1Range9Delete90Store900Load/sync.Map-16 1.00µs ±12% 101 String/Store/skipmap-16 171ns ±15% 102 String/Store/sync.Map-16 873ns ± 4% 103 String/Load50Hits/skipmap-16 21.3ns ±38% 104 String/Load50Hits/sync.Map-16 19.9ns ±12% 105 String/30Store70Load/skipmap-16 75.6ns ±16% 106 String/30Store70Load/sync.Map-16 726ns ± 5% 107 String/1Delete9Store90Load/skipmap-16 34.3ns ±20% 108 String/1Delete9Store90Load/sync.Map-16 584ns ± 5% 109 String/1Range9Delete90Store900Load/skipmap-16 41.0ns ±21% 110 String/1Range9Delete90Store900Load/sync.Map-16 1.17µs ± 8% 111 112 name alloc/op 113 Int64/Store/skipmap-16 112B ± 0% 114 Int64/Store/sync.Map-16 128B ± 0% 115 Int64/Load50Hits/skipmap-16 0.00B 116 Int64/Load50Hits/sync.Map-16 0.00B 117 Int64/30Store70Load/skipmap-16 33.0B ± 0% 118 Int64/30Store70Load/sync.Map-16 81.2B ±11% 119 Int64/1Delete9Store90Load/skipmap-16 10.0B ± 0% 120 Int64/1Delete9Store90Load/sync.Map-16 57.9B ± 5% 121 Int64/1Range9Delete90Store900Load/skipmap-16 10.0B ± 0% 122 Int64/1Range9Delete90Store900Load/sync.Map-16 261B ±17% 123 String/Store/skipmap-16 144B ± 0% 124 String/Store/sync.Map-16 152B ± 0% 125 String/Load50Hits/skipmap-16 15.0B ± 0% 126 String/Load50Hits/sync.Map-16 15.0B ± 0% 127 String/30Store70Load/skipmap-16 54.0B ± 0% 128 String/30Store70Load/sync.Map-16 96.9B ±12% 129 String/1Delete9Store90Load/skipmap-16 27.0B ± 0% 130 String/1Delete9Store90Load/sync.Map-16 74.2B ± 4% 131 String/1Range9Delete90Store900Load/skipmap-16 27.0B ± 0% 132 String/1Range9Delete90Store900Load/sync.Map-16 257B ±10% 133 134 name allocs/op 135 Int64/Store/skipmap-16 3.00 ± 0% 136 Int64/Store/sync.Map-16 4.00 ± 0% 137 Int64/Load50Hits/skipmap-16 0.00 138 Int64/Load50Hits/sync.Map-16 0.00 139 Int64/30Store70Load/skipmap-16 0.00 140 Int64/30Store70Load/sync.Map-16 1.00 ± 0% 141 Int64/1Delete9Store90Load/skipmap-16 0.00 142 Int64/1Delete9Store90Load/sync.Map-16 0.00 143 Int64/1Range9Delete90Store900Load/skipmap-16 0.00 144 Int64/1Range9Delete90Store900Load/sync.Map-16 0.00 145 String/Store/skipmap-16 4.00 ± 0% 146 String/Store/sync.Map-16 5.00 ± 0% 147 String/Load50Hits/skipmap-16 1.00 ± 0% 148 String/Load50Hits/sync.Map-16 1.00 ± 0% 149 String/30Store70Load/skipmap-16 1.00 ± 0% 150 String/30Store70Load/sync.Map-16 2.00 ± 0% 151 String/1Delete9Store90Load/skipmap-16 1.00 ± 0% 152 String/1Delete9Store90Load/sync.Map-16 1.00 ± 0% 153 String/1Range9Delete90Store900Load/skipmap-16 1.00 ± 0% 154 String/1Range9Delete90Store900Load/sync.Map-16 1.00 ± 0% 155 ```