]> 127.0.0.1 Git - part/.git/commitdiff
syncMap v0.4.1
authorqydysky <qydysky@foxmail.com>
Wed, 17 Feb 2021 16:24:18 +0000 (00:24 +0800)
committerqydysky <qydysky@foxmail.com>
Wed, 17 Feb 2021 16:24:18 +0000 (00:24 +0800)
map/Map.go [new file with mode: 0644]
map/Map_test.go [new file with mode: 0644]

diff --git a/map/Map.go b/map/Map.go
new file mode 100644 (file)
index 0000000..16d9c81
--- /dev/null
@@ -0,0 +1,132 @@
+package part
+
+import (
+       "unsafe"
+       "runtime"
+       "sync/atomic"
+)
+
+type Map struct {
+       lock pLock //sync
+       num int
+       m map[interface{}]*ptr
+       readOnly atomic.Value //sync
+}
+
+func (t *Map) Store(k,v interface{}) {
+
+       m,_ := t.readOnly.Load().(map[interface{}]*ptr)
+       if p,ok := m[k];ok{
+               p.tryStore(&v)
+               return
+       }
+
+       t.lock.Lock()
+
+       m,_ = t.readOnly.Load().(map[interface{}]*ptr)
+       if p,ok := m[k];ok{
+               p.tryStore(&v)
+       } else if p,ok := t.m[k];ok{
+               p.tryStore(&v)
+       } else {
+               if t.m == nil {t.mapFrom(&m)}
+               t.m[k] = &ptr{p:unsafe.Pointer(&v)}
+               t.num += 1
+       }
+
+       t.lock.Unlock()
+}
+
+func (t *Map) Load(k interface{}) (v interface{}) {
+
+       m,_ := t.readOnly.Load().(map[interface{}]*ptr)
+       p,ok := m[k]
+       if !ok && t.num != 0{
+               t.lock.Lock()
+
+               m,_ = t.readOnly.Load().(map[interface{}]*ptr)
+               p,ok = m[k]
+               if !ok && t.num != 0{
+                       if t.m == nil {t.mapFrom(&m)}
+                       p,ok = t.m[k]
+                       if ok && t.num > 1e3{
+                               t.readOnly.Store(t.m)
+                               t.m = nil
+                               t.num = 0
+                       }
+               }
+       
+               t.lock.Unlock()
+       }
+
+       if !ok{
+               return nil
+       }
+
+       return p.tryLoad()
+}
+
+func (t *Map) Delete(k interface{}) {
+       m,_ := t.readOnly.Load().(map[interface{}]*ptr)
+       
+       if p,ok := m[k];ok && p != nil{
+               delete(m, k)
+               return
+       }
+
+       t.lock.Lock()
+
+       delete(t.m, k)
+
+       t.lock.Unlock()
+}
+
+func (t *Map) Len() int {
+       m,_ := t.readOnly.Load().(map[interface{}]*ptr)
+       return len(m) + t.num
+}
+
+func (t *Map) mapFrom(from *map[interface{}]*ptr) {
+       if t.m == nil {t.m = make(map[interface{}]*ptr)}
+       for k,v := range *from{
+               if v == nil {continue}
+               t.m[k] = v
+       }
+}
+
+type ptr struct {
+       p unsafe.Pointer
+}
+
+func (t *ptr) tryStore(v *interface{}) {
+       t.p = unsafe.Pointer(v)
+       // atomic.StorePointer(&t.p, unsafe.Pointer(v))
+}
+
+func (t *ptr) tryLoad() (interface{}) {
+       // p := atomic.LoadPointer(&t.p)
+       if t.p == nil{
+               return nil
+       }
+       return *(*interface{})(t.p)
+}
+
+type pLock struct{
+       i unsafe.Pointer
+       busy unsafe.Pointer
+}
+
+func (l *pLock) Lock() {
+       if l.busy == nil{l.busy = unsafe.Pointer(&struct{}{})}
+       for !atomic.CompareAndSwapPointer(&l.i, nil, l.busy) {
+               runtime.Gosched()
+       }
+}
+
+func (l *pLock) Locking() (bool) {
+       return atomic.LoadPointer(&l.i) != nil
+}
+
+func (l *pLock) Unlock() {
+       atomic.CompareAndSwapPointer(&l.i, l.busy, nil)
+}
diff --git a/map/Map_test.go b/map/Map_test.go
new file mode 100644 (file)
index 0000000..d5aa198
--- /dev/null
@@ -0,0 +1,218 @@
+package part
+
+import (
+       "sync"
+       "testing"
+)
+
+func Test_customMap(t *testing.T) {
+       var c Map
+       //set
+       c.Store(0, 3)
+       if c.Load(0) != 3{t.Error(`1`)}
+       //change
+       c.Store(0, 1)
+       if c.Load(0) != 1{t.Error(`2`)}
+       //del
+       c.Store(0, nil)
+       if c.Load(0) != nil{t.Error(`3`)}
+}
+
+func Benchmark_customMap_Set(b *testing.B) {
+       var c Map
+       var w = &sync.WaitGroup{}
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, nil)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+}
+
+func Benchmark_customMap_Del(b *testing.B) {
+       c := new(Map)
+       var w = &sync.WaitGroup{}
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, 0)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Delete(index)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+}
+
+func Benchmark_customMap_Get(b *testing.B) {
+       var c Map
+       var w = &sync.WaitGroup{}
+       var t = b.N
+       
+       w.Add(t)
+       b.ResetTimer()
+       for i := 0; i < t; i++ {
+               go func(index int) {
+                       c.Store(index, index)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+
+       b.ResetTimer()
+
+       w.Add(t)
+       b.ResetTimer()
+       for i := 0; i < t; i++ {
+               go func(index int) {
+                       if c.Load(index).(int) != index {
+                               b.Error("q")
+                       }
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+}
+
+func Benchmark_customMap_SetGet(b *testing.B) {
+       var c Map
+       var w = &sync.WaitGroup{}
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, index)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+
+       b.Log(c.Len())
+
+       w.Add(b.N)
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, index+1)
+                       w.Done()
+               }(i)
+               go func(index int) {
+                       if t,ok := c.Load(index).(int);!ok || t != index && t != index+1{
+                               b.Error(`E`, index, t)
+                       }
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+}
+
+func Benchmark_syncMap_Set(b *testing.B) {
+       c:=new(sync.Map)
+       var w = &sync.WaitGroup{}
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, nil)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+ }
+
+ func Benchmark_syncMap_Del(b *testing.B) {
+       c := new(sync.Map)
+       var w = &sync.WaitGroup{}
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, 0)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Delete(index)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+}
+
+func Benchmark_syncMap_Get(b *testing.B) {
+       c := new(sync.Map)
+       var w = &sync.WaitGroup{}
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, 0)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       if v,ok := c.Load(index);!ok || v.(int) != 0 {b.Error("q")}
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+}
+
+func Benchmark_syncMap_SetGet(b *testing.B) {
+       c := new(sync.Map)
+       var w = &sync.WaitGroup{}
+
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, 0)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+
+       w.Add(b.N)
+       w.Add(b.N)
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               go func(index int) {
+                       c.Store(index, 1)
+                       w.Done()
+               }(i)
+               go func(index int) {
+                       c.Load(index)
+                       w.Done()
+               }(i)
+       }
+       w.Wait()
+}