Go 中使用 map 实现高效的数据缓存

简介: Go 中使用 map 实现高效的数据缓存

在 Go 语言中,使用 map 结合 LRU(Least Recently Used) 缓存算法,可以实现高效的数据缓存。以下是一个示例实现:

import (
    "container/list"
    "sync"
)

type Cache struct {
   
    capacity int
    mu       sync.Mutex
    list     *list.List
    m        map[string]*list.Element
}

type entry struct {
   
    key   string
    value interface{
   }
}

func NewCache(capacity int) *Cache {
   
    return &Cache{
   
        capacity: capacity,
        list:     list.New(),
        m:        make(map[string]*list.Element, capacity),
    }
}

func (c *Cache) Get(key string) (value interface{
   }, ok bool) {
   
    c.mu.Lock()
    defer c.mu.Unlock()

    if elem, ok := c.m[key]; ok {
   
        c.list.MoveToFront(elem)
        return elem.Value.(*entry).value, true
    }
    return nil, false
}

func (c *Cache) Put(key string, value interface{
   }) {
   
    c.mu.Lock()
    defer c.mu.Unlock()

    if elem, ok := c.m[key]; ok {
   
        c.list.MoveToFront(elem)
        elem.Value.(*entry).value = value
        return
    }

    if c.list.Len() == c.capacity {
   
        old := c.list.Back()
        c.list.Remove(old)
        delete(c.m, old.Value.(*entry).key)
    }

    elem := c.list.PushFront(&entry{
   key, value})
    c.m[key] = elem
}

这个缓存实现使用了 sync.Mutex 来确保线程安全,并使用 container/list 包中的双向链表来维护 LRU 顺序。

主要流程如下:

  1. Get(key) 方法先获取读锁,然后在 map 中查找键对应的值。如果找到,则将对应的链表节点移到链表头部,并返回值。
  2. Put(key, value) 方法先获取写锁,然后在 map 中查找键是否存在:
    • 如果存在,则将对应的链表节点移到链表头部,并更新值。
    • 如果不存在且缓存已满,则删除链表末尾的节点及其在 map 中的记录,然后添加新的节点到链表头部。

这种结构可以提供 O(1) 时间复杂度的 GetPut 操作,并能自动淘汰最久未使用的数据,非常适用于缓存场景。

此外,您也可以使用 Go 标准库中的 sync.Map 类型,它自带了并发安全的 LoadStoreDelete 方法,从而无需自行实现锁机制。

相关文章
|
1月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
|
1月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
|
28天前
|
存储 Java API
深入剖析Java Map:不只是存储数据,更是设计艺术的体现!
【10月更文挑战第17天】在Java编程中,Map是一种重要的数据结构,用于存储键值对,并展现了设计艺术的精髓。本文深入剖析了Map的设计原理和使用技巧,包括基本概念、设计艺术(如哈希表与红黑树的空间时间权衡)、以及使用技巧(如选择合适的实现类、避免空指针异常等),帮助读者更好地理解和应用Map。
81 3
|
19天前
|
存储 缓存 算法
分布式缓存有哪些常用的数据分片算法?
【10月更文挑战第25天】在实际应用中,需要根据具体的业务需求、数据特征以及系统的可扩展性要求等因素综合考虑,选择合适的数据分片算法,以实现分布式缓存的高效运行和数据的合理分布。
|
1月前
|
缓存 监控 前端开发
处理页面缓存中数据不一致的问题
【10月更文挑战第9天】
42 2
|
1月前
|
消息中间件 缓存 NoSQL
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
52 2
|
2月前
|
Go 定位技术 索引
Go 语言Map(集合) | 19
Go 语言Map(集合) | 19
|
3月前
|
数据采集 缓存 IDE
Go中遇到http code 206和302的获取数据的解决方案
文章提供了解决Go语言中处理HTTP状态码206(部分内容)和302(重定向)的方案,包括如何获取部分数据和真实请求地址的方法,以便程序员能快速完成工作,享受七夕时光。
172 0
Go中遇到http code 206和302的获取数据的解决方案
|
3月前
|
存储 缓存 Go
如何检查 Go map 是否包含某个键?
【8月更文挑战第31天】
31 0
|
3月前
|
存储 Go 容器
Go从入门到放弃之map(字典)
Go从入门到放弃之map(字典)