mossxzzom

缓存如果写满, 它必须淘汰旧值以容纳新值, 最近最少使用淘汰算法 (LRU) 是一个不错的选择, 因为你如果最近使用过某些值, 这些值更可能被保留. 你如果构造一个比缓存限制还长的循环, 当循环最后的值可以命中缓存时, LRU 就会是完美的, 但是当它无法命中缓存时, 这个缓存将失效. 缓存的淘汰算法也要降级为随机淘汰算法.

image

基于 sync.Mapmap 的无序遍历机制, 带有 过期时间 的随机淘汰缓存可以非常轻松被实现.

实现

构造器

type Item struct {
	item   interface{}
	exired int64
}

type Cache struct {
	cache *sync.Map
	limit int64
	size  int64
}

func NewCache(limit int64) *Cache {
	if limit <= 0 {
		log.Panicf("cache.NewCache.limit:%+v <= 0", limit)
	}
	return &Cache{cache: &sync.Map{}, limit: limit}
}

接口以及实现

func (c *Cache) Get(key interface{}) (interface{}, bool) {
	if val, ok := c.cache.Load(key); !ok {
		return nil, false
	} else if item, _ := val.(*Item); item.exired <= 0 || time.Now().Unix() < item.exired {
		return item.item, true
	} else {
		c.cache.Delete(key)
		atomic.AddInt64(&c.size, -1)
		return nil, false
	}
}

func (c *Cache) Set(key, val interface{}, exired int64) {
	if _, ok := c.cache.Load(key); ok && val != nil {
		c.cache.Store(key, &Item{val, exired})
		return
	} else if ok && val == nil {
		c.cache.Delete(key)
		atomic.AddInt64(&c.size, -1)
		return
	} else if (c.limit <= c.size && c.deleteAnother(key)) || c.size < c.limit {
		c.cache.Store(key, &Item{val, exired})
		return
	}
}

func (c *Cache) Size() int64 {
	return c.size
}

Random淘汰算法

基于 go 对 map 的无序遍历机制

func (c *Cache) deleteAnother(key interface{}) (found bool) {
	c.cache.Range(func(other, value interface{}) bool {
		if key == other {
			return true
		}
		found = true
		c.cache.Delete(other)
		return false
	})
	return found
}

实例

  1. aws-sdk-go缓存 Endpoint 对象.

参考

[1] Caches: LRU v. random [EB/OL]. https://danluu.com/2choices-eviction/.

分类:

技术点:

相关文章:

  • 2021-12-24
  • 2021-05-21
  • 2021-10-26
猜你喜欢
  • 2021-08-03
  • 2021-11-13
  • 2021-09-06
  • 2021-05-22
  • 2022-12-23
相关资源
相似解决方案