Last active
May 9, 2024 03:50
-
-
Save phuslu/1423aee3127b85ed479c1431551f3c5c to your computer and use it in GitHub Desktop.
双缓冲实现无锁map,读取性能和GC友好度最好,一致性较差,写入延迟一般建议设置为分钟级。 https://twitter.com/phuslu/status/1745276311235395708
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type CachingMap[K comparable, V any] struct { | |
// double buffering mechanism | |
index int64 | |
maps [2]map[K]V | |
// write queue | |
queue chan struct { | |
key K | |
value V | |
} | |
getter func(K) (V, error) | |
maxsize int | |
duration time.Duration | |
} | |
func NewCachingMap[K comparable, V any](getter func(K) (V, error), maxsize int, duration time.Duration) *CachingMap[K, V] { | |
cm := &CachingMap[K, V]{ | |
index: 0, | |
maps: [2]map[K]V{ | |
make(map[K]V), | |
make(map[K]V), | |
}, | |
queue: make(chan struct { | |
key K | |
value V | |
}, 1024), | |
getter: getter, | |
maxsize: maxsize, | |
duration: duration, | |
} | |
go func(cm *CachingMap[K, V]) { | |
duration := cm.duration | |
if duration == 0 { | |
duration = time.Minute | |
} | |
ticker := time.NewTicker(duration) | |
for { | |
select { | |
case kv := <-cm.queue: | |
cm.maps[(atomic.LoadInt64(&cm.index)+1)%2][kv.key] = kv.value | |
case <-ticker.C: | |
atomic.StoreInt64(&cm.index, (atomic.LoadInt64(&cm.index)+1)%2) | |
if m := cm.maps[(atomic.LoadInt64(&cm.index)+1)%2]; maxsize <= 0 || len(m) <= maxsize { | |
for key, value := range cm.maps[atomic.LoadInt64(&cm.index)] { | |
m[key] = value | |
} | |
} else { | |
cm.maps[(atomic.LoadInt64(&cm.index)+1)%2] = make(map[K]V) | |
} | |
} | |
} | |
}(cm) | |
return cm | |
} | |
func (cm *CachingMap[K, V]) Get(key K) (value V, ok bool, err error) { | |
// fast path, lock-free | |
value, ok = cm.maps[atomic.LoadInt64(&cm.index)][key] | |
if ok { | |
return | |
} | |
// slow path | |
value, err = cm.getter(key) | |
if err == nil { | |
cm.queue <- struct { | |
key K | |
value V | |
}{key, value} | |
} | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment