zoukankan      html  css  js  c++  java
  • 使用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();
    }
    

      

  • 相关阅读:
    进程与线程
    the art of seo(chapter seven)
    the art of seo(chapter six)
    the art of seo(chapter five)
    the art of seo(chapter four)
    the art of seo(chapter three)
    the art of seo(chapter two)
    the art of seo(chapter one)
    Sentinel Cluster流程分析
    Sentinel Core流程分析
  • 原文地址:https://www.cnblogs.com/jkko123/p/6971133.html
Copyright © 2011-2022 走看看