使用go语言的list实现一个简单的LRU缓存

package main;

import (
	"container/list"
	"errors"
	"sync"
	"fmt"
	"encoding/json"
)

//LRU(Least recently used)最近最少使用,算法根据数据的历史访问记录来进行淘汰数据
//核心思想是"如果数据最近被访问过,那么将来被访问的几率也更高"
//常见的实现方式是用一个链表保存数据
//1. 新数据插入到链表头部
//2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部
//3. 当链表满的时候,将链表尾部的数据丢弃

type cacheItem struct {
	Key string;
	Val interface{};
}

type LRU struct {
	//最大存储数量
	maxNum int;
	//当前存储数量
	curNum int;
	//锁,保证数据一致性
	mutex  sync.Mutex;
	//链表
	data   *list.List;
}

//添加数据
func (l *LRU) add(key string, value interface{}) error {
	//判断key是否存在
	if e, _ := l.exist(key); e {
		return errors.New(key + "已存在");
	}
	//判断当前存储数量与最大存储数量
	if l.maxNum == l.curNum {
		//链表已满,则删除链表尾部元素
		l.clear();
	}
	l.mutex.Lock();
	l.curNum++;
	//json序列化数据
	data, _ := json.Marshal(cacheItem{key, value});
	//把数据保存到链表头部
	l.data.PushFront(data);
	l.mutex.Unlock();
	return nil;
}

//设置数据
func (l *LRU) set(key string, value interface{}) error {
	e, item := l.exist(key);
	if !e {
		return l.add(key, value);
	}
	l.mutex.Lock();
	data, _ := json.Marshal(cacheItem{key, value});
	//设置链表元素数据
	item.Value = data;
	l.mutex.Unlock();
	return nil;
}

//清理数据
func (l *LRU) clear() interface{} {
	l.mutex.Lock();
	l.curNum--;
	//删除链表尾部元素
	v := l.data.Remove(l.data.Back());
	l.mutex.Unlock();
	return v;
}

//获取数据
func (l *LRU) get(key string) interface{} {
	e, item := l.exist(key);
	if !e {
		return nil;
	}
	l.mutex.Lock();
	//数据被访问,则把元素移动到链表头部
	l.data.MoveToFront(item);
	l.mutex.Unlock();
	var data cacheItem;
	json.Unmarshal(item.Value.([]byte), &data);
	return data.Val;
}

//删除数据
func (l *LRU) del(key string) error {
	e, item := l.exist(key);
	if !e {
		return errors.New(key + "不存在");
	}
	l.mutex.Lock();
	l.curNum--;
	//删除链表元素
	l.data.Remove(item);
	l.mutex.Unlock();
	return nil;
}

//判断是否存在
func (l *LRU) exist(key string) (bool, *list.Element) {
	var data cacheItem;
	//循环链表,判断key是否存在
	for v := l.data.Front(); v != nil; v = v.Next() {
		json.Unmarshal(v.Value.([]byte), &data);
		if key == data.Key {
			return true, v;
		}
	}
	return false, nil;
}

//返回长度
func (l *LRU) len() int {
	return l.curNum;
}

//打印链表
func (l *LRU) print() {
	var data cacheItem;
	for v := l.data.Front(); v != nil; v = v.Next() {
		json.Unmarshal(v.Value.([]byte), &data);
		fmt.Println("key:", data.Key, " value:", data.Val);
	}
}

//创建一个新的LRU
func LRUNew(maxNum int) *LRU {
	return &LRU{
		maxNum: maxNum,
		curNum: 0,
		mutex:  sync.Mutex{},
		data:   list.New(),
	};
}

func main() {
	lru := LRUNew(5);
	lru.add("1111", 1111);
	lru.add("2222", 2222);
	lru.add("3333", 3333);
	lru.add("4444", 4444);
	lru.add("5555", 5555);
	lru.print();
	//get成功后,可以看到3333元素移动到了链表头
	fmt.Println(lru.get("3333"));
	lru.print();
	//再次添加元素,如果超过最大数量,则删除链表尾部元素,将新元素添加到链表头
	lru.add("6666", 6666);
	lru.print();
	lru.del("4444");
	lru.print();
	lru.set("2222", "242424");
	lru.print();
}

  

原文地址:https://www.cnblogs.com/jkko123/p/6971133.html