github.com/songzhibin97/gkit@v1.2.13/structure/skipset/README.md (about) 1 ## Introduction 2 3 skipset is a high-performance concurrent set based on skip list. In typical pattern(100000 operations, 90%CONTAINS 9%ADD 4 1%REMOVE), the skipset up to 3x ~ 15x faster than the built-in sync.Map. 5 6 The main idea behind the skipset 7 is [A Simple Optimistic Skiplist Algorithm](<https://people.csail.mit.edu/shanir/publications/LazySkipList.pdf>). 8 9 Different from the sync.Map, the items in the skipset are always sorted, and the `Contains` and `Range` operations are 10 wait-free (A goroutine is guaranteed to complete an operation as long as it keeps taking steps, regardless of the 11 activity of other goroutines). 12 13 ## Features 14 15 - Concurrent safe API with high-performance. 16 - Wait-free Contains and Range operations. 17 - Sorted items. 18 19 ## When should you use skipset 20 21 In these situations, `skipset` is better 22 23 - **Sorted elements is needed**. 24 - **Concurrent calls multiple operations**. such as use both `Contains` and `Add` at the same time. 25 - **Memory intensive**. The skipset save at least 50% memory in the benchmark. 26 27 In these situations, `sync.Map` is better 28 29 - Only one goroutine access the set for most of the time, such as insert a batch of elements and then use 30 only `Contains` (use built-in map is even better). 31 32 ## QuickStart 33 34 ```go 35 package main 36 37 import ( 38 "fmt" 39 40 "github.com/songzhibin97/gkit/structure/skipset" 41 ) 42 43 func main() { 44 l := NewInt() 45 46 for _, v := range []int{10, 12, 15} { 47 if l.Add(v) { 48 fmt.Println("skipset add", v) 49 } 50 } 51 52 if l.Contains(10) { 53 fmt.Println("skipset contains 10") 54 } 55 56 l.Range(func(value int) bool { 57 fmt.Println("skipset range found ", value) 58 return true 59 }) 60 61 l.Remove(15) 62 fmt.Printf("skipset contains %d items\r\n", l.Len()) 63 } 64 65 ``` 66 67 ## Benchmark 68 69 Go version: go1.16.2 linux/amd64 70 71 CPU: AMD 3700x(8C16T), running at 3.6GHz 72 73 OS: ubuntu 18.04 74 75 MEMORY: 16G x 2 (3200MHz) 76 77 ![benchmark](https://raw.githubusercontent.com/zhangyunhao116/public-data/master/skipset-benchmark.png) 78 79 ```shell 80 $ go test -run=NOTEST -bench=. -benchtime=100000x -benchmem -count=20 -timeout=60m > x.txt 81 $ benchstat x.txt 82 ``` 83 84 ``` 85 name time/op 86 Int64/Add/skipset-16 86.6ns ±11% 87 Int64/Add/sync.Map-16 674ns ± 6% 88 Int64/Contains50Hits/skipset-16 9.85ns ±12% 89 Int64/Contains50Hits/sync.Map-16 14.7ns ±30% 90 Int64/30Add70Contains/skipset-16 38.8ns ±18% 91 Int64/30Add70Contains/sync.Map-16 586ns ± 5% 92 Int64/1Remove9Add90Contains/skipset-16 24.9ns ±17% 93 Int64/1Remove9Add90Contains/sync.Map-16 493ns ± 5% 94 Int64/1Range9Remove90Add900Contains/skipset-16 25.9ns ±16% 95 Int64/1Range9Remove90Add900Contains/sync.Map-16 1.00µs ±12% 96 String/Add/skipset-16 130ns ±14% 97 String/Add/sync.Map-16 878ns ± 4% 98 String/Contains50Hits/skipset-16 18.3ns ± 9% 99 String/Contains50Hits/sync.Map-16 19.2ns ±18% 100 String/30Add70Contains/skipset-16 61.0ns ±15% 101 String/30Add70Contains/sync.Map-16 756ns ± 7% 102 String/1Remove9Add90Contains/skipset-16 31.3ns ±13% 103 String/1Remove9Add90Contains/sync.Map-16 614ns ± 6% 104 String/1Range9Remove90Add900Contains/skipset-16 36.2ns ±18% 105 String/1Range9Remove90Add900Contains/sync.Map-16 1.20µs ±17% 106 107 name alloc/op 108 Int64/Add/skipset-16 65.0B ± 0% 109 Int64/Add/sync.Map-16 128B ± 1% 110 Int64/Contains50Hits/skipset-16 0.00B 111 Int64/Contains50Hits/sync.Map-16 0.00B 112 Int64/30Add70Contains/skipset-16 19.0B ± 0% 113 Int64/30Add70Contains/sync.Map-16 77.7B ±16% 114 Int64/1Remove9Add90Contains/skipset-16 5.00B ± 0% 115 Int64/1Remove9Add90Contains/sync.Map-16 57.5B ± 4% 116 Int64/1Range9Remove90Add900Contains/skipset-16 5.00B ± 0% 117 Int64/1Range9Remove90Add900Contains/sync.Map-16 255B ±22% 118 String/Add/skipset-16 97.0B ± 0% 119 String/Add/sync.Map-16 152B ± 0% 120 String/Contains50Hits/skipset-16 15.0B ± 0% 121 String/Contains50Hits/sync.Map-16 15.0B ± 0% 122 String/30Add70Contains/skipset-16 40.0B ± 0% 123 String/30Add70Contains/sync.Map-16 98.2B ±11% 124 String/1Remove9Add90Contains/skipset-16 23.0B ± 0% 125 String/1Remove9Add90Contains/sync.Map-16 73.9B ± 4% 126 String/1Range9Remove90Add900Contains/skipset-16 23.0B ± 0% 127 String/1Range9Remove90Add900Contains/sync.Map-16 261B ±18% 128 129 name allocs/op 130 Int64/Add/skipset-16 1.00 ± 0% 131 Int64/Add/sync.Map-16 4.00 ± 0% 132 Int64/Contains50Hits/skipset-16 0.00 133 Int64/Contains50Hits/sync.Map-16 0.00 134 Int64/30Add70Contains/skipset-16 0.00 135 Int64/30Add70Contains/sync.Map-16 1.00 ± 0% 136 Int64/1Remove9Add90Contains/skipset-16 0.00 137 Int64/1Remove9Add90Contains/sync.Map-16 0.00 138 Int64/1Range9Remove90Add900Contains/skipset-16 0.00 139 Int64/1Range9Remove90Add900Contains/sync.Map-16 0.00 140 String/Add/skipset-16 2.00 ± 0% 141 String/Add/sync.Map-16 5.00 ± 0% 142 String/Contains50Hits/skipset-16 1.00 ± 0% 143 String/Contains50Hits/sync.Map-16 1.00 ± 0% 144 String/30Add70Contains/skipset-16 1.00 ± 0% 145 String/30Add70Contains/sync.Map-16 2.00 ± 0% 146 String/1Remove9Add90Contains/skipset-16 1.00 ± 0% 147 String/1Remove9Add90Contains/sync.Map-16 1.00 ± 0% 148 String/1Range9Remove90Add900Contains/skipset-16 1.00 ± 0% 149 String/1Range9Remove90Add900Contains/sync.Map-16 1.00 ± 0% 150 ```