golang 实现cache
1. 支持 set get 方法,有容量 和 过期时间配置项
2. 数据带过期时间,过期自动老化
3. lru 机制,当达到总量时,删除掉最晚被访问的数据
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("hello world!")
cache := NewCache(10, 5)
fmt.Println(" now timestamp: ", time.Now().Unix())
cache.Put(1, 2)
fmt.Println(cache.Get(1))
time.Sleep(6 * time.Second)
fmt.Println(cache.Get(1))
}
type Cache struct {
head, tail *entry
cache map[int]*entry
capacity int
ttl int
}
type entry struct {
key, value int
expire int
prev, next *entry
}
func NewCache(capacity, ttl int) *Cache {
return &Cache{
cache: make(map[int]*entry),
capacity: capacity,
ttl: ttl,
}
}
func (c *Cache) Get(key int) int {
if elem, ok := c.cache[key]; ok {
if elem.expire < int(time.Now().Unix()) {
delete(c.cache, elem.key)
return -1
}
// 更新节点位置
c.moveToHead(elem)
return elem.value
}
return -1
}
func (c *Cache) moveToHead(elem *entry) {
if elem == c.head {
return
} else if elem == c.tail {
c.tail = elem.prev
} else {
elem.prev.next = elem.next
elem.next.prev = elem.prev
}
elem.prev = nil
elem.next = c.head
c.head.prev = elem
c.head = elem
}
func (c *Cache) Put(key, value int) {
if elem, ok := c.cache[key]; ok {
elem.value = value
c.moveToHead(elem)
} else {
// 创建新节点
elem := &entry{
key: key,
value: value,
expire: int(time.Now().Unix()) + c.ttl,
}
c.cache[key] = elem
if c.head == nil {
c.head = elem
c.tail = elem
} else {
// 在链表头插入新节点
elem.next = c.head
c.head.prev = elem
c.head = elem
}
// 判断缓存是否达到预设上限
if len(c.cache) > c.capacity {
// 删除链表尾部节点和哈希表中的数据
delete(c.cache, c.tail.key)
c.tail = c.tail.prev
c.tail.next = nil
}
}
}