c语言编程笔录

首页 >   > 笔记大全

笔记大全

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()
        }
    }