golang 缓存实现
更新时间:2023-07-13缓存是什么?
缓存是在计算机中存储数据的临时区域。这些数据存储在缓存中,以便更快地访问和操作。在计算机工作中,数据从硬盘中读取通常会比从内存读取要慢很多,因为硬盘的访问速度比内存慢很多。因此,缓存可以帮助程序员更快地处理和操作数据。
Go语言中的缓存实现
在Go语言中,可以通过使用map来实现缓存。map是Go语言的一种高效数据结构,利用哈希表实现存储和获取数据的操作。
cache := make(map[string]string) cache["apple"] = "red" cache["banana"] = "yellow" fmt.Println(cache["apple"]) // 输出 "red"
基于时间的缓存失效
为了防止缓存中的数据被过时的数据所替代,我们需要在缓存中设置一个失效时间。在Go语言中,我们可以使用time包的Duration类型来表示时间段。
type Cache struct { data map[string]CacheItem } type CacheItem struct { value interface{} expiration time.Time } func (c *Cache) Get(key string) interface{} { item, found := c.data[key] if !found { return nil } if time.Now().Sub(item.expiration) > 0 { return nil } return item.value } func (c *Cache) Put(key string, value interface{}, duration time.Duration) { c.data[key] = CacheItem{ value: value, expiration: time.Now().Add(duration), } }
基于LRU算法的缓存淘汰
在缓存中存储的数据量可能会非常大,因此需要在缓存中设置一种策略来选择缓存中要删除的数据。一种被广泛使用的策略是LRU(Least Recently Used)。LRU算法会删除最近最少使用的数据。
type Cache struct { underlyingMap map[string]*list.Element evictionList *list.List evictionListMaxSize int defaultExpiration time.Duration cleanupTimerDuration time.Duration } type cacheItem struct { key string value interface{} expiration *time.Time evictionList *list.List } func (c *Cache) evict() { for { if element := c.evictionList.Back(); element != nil { oldestItem := element.Value.(*cacheItem) if oldestItem.expiration == nil || oldestItem.expiration.Before(time.Now()) { c.deleteOldestItem() } else { return } } else { return } } } func (c *Cache) Get(key string) (interface{}, bool) { if val, ok := c.underlyingMap[key]; ok { item := val.Value.(*cacheItem) if item.expiration != nil && item.expiration.Before(time.Now()) { c.delete(key) return nil, false } c.evictionList.MoveToFront(item.evictionList) return item.value, true } else { return nil, false } } func (c *Cache) delete(key string) bool { if val, ok := c.underlyingMap[key]; ok { c.deleteInternal(val) return true } return false } func (c *Cache) add(key string, value interface{}, expiration *time.Time) { if c.evictionListMaxSize > 0 && c.evictionList.Len() == c.evictionListMaxSize { c.deleteOldestItem() } item := &cacheItem{ key: key, value: value, expiration: expiration, evictionList: c.evictionList.PushFront(nil), } item.evictionList.Value = item c.underlyingMap[key] = item.evictionList if expiration != nil && (c.cleanupTimerDuration <= 0 || c.evictionListMaxSize <= 0) { c.scheduleExpirationCleanup() } }