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

  

使用go语言的list实现一个简单的LRU缓存的更多相关文章

  1. C语言中如何写一个简单可移植而又足够随机的随机数生成器

    在C语言中标准库中的随机数产生函数的返回可能不是最优的,因为有些随机数生成器的低位并不随机,而另一些返回随机数的函数实现上又太复杂鸟.所以rand()%N并不是一个好方法,牛人给出的建议是使用: ra ...

  2. 一个简单的带缓存http代理

    眼下1.0版模型非常easy.即对客户机发来的请求进行简单处理后,转发到server.转发之前先检查本地缓存.假设有.则直接回送给客户本地资源 程序流程大致例如以下图: 缓存是通过把文件保存到磁盘上, ...

  3. 搭建一个简单的dns缓存服务器

    环境:linux 软件:bind97,bind97-utils, bind97-libs ip:192.168.192.130:192.168.192.131 -------------------- ...

  4. C#简单实现LRU缓存

    最近跟同学吃饭扯淡的时候,由技术扯到薪资,又由薪资扯到他找工作时跟面试官是怎么扯淡拿高工资的,各种技术一顿侃,总之只要啥都了解就没问题了.谈到缓存的时候,我试探性的问了问- -你还记得LRU怎么写吗, ...

  5. Golang校招简历项目-简单的分布式缓存

    前言 前段时间,校招投了golang岗位,但是没什么好的项目往简历上写,于是参考了许多网上资料,做了一个简单的分布式缓存项目. 现在闲下来了,打算整理下. github项目地址:https://git ...

  6. 为什么C语言在2013年仍然很重要:一个简单的例子

    附注:在最初的文章里,我没说明进行模2^64的计算——我当然明白那些不是“正确的”斐波那契数列,其实我不是想分析大数,我只是想探寻编译器产生的代码和计算机体系结构而已. 最近,我一直在开发Dynvm— ...

  7. 一个简单的C语言程序(详解)

    C Primer Plus之一个简单的C语言程序(详解) #include <stdio.h> int main(void) //一个简单的 C程序 { int num; //定义一个名为 ...

  8. 用C语言编写一个简单的词法分析程序

    问题描述: 用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表.如果产生词法错误,则显示错误信息.位置,并试图从错误中恢复.简单的恢复方法 ...

  9. 用Go语言实现一个简单的聊天机器人

    一.介绍 目的:使用Go语言写一个简单的聊天机器人,复习整合Go语言的语法和基础知识. 软件环境:Go1.9,Goland 2018.1.5. 二.回顾 Go语言基本构成要素:标识符.关键字.字面量. ...

随机推荐

  1. RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World(转载)

    RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World 一.简介 RabbitMQ是一个消息的代理器,用于接收和发送消息,你可以这样想,他就是一个邮局,当您把需要寄送的邮件投递到 ...

  2. 今天折腾phantomjs+selenium的笔记

    1.debian8里安装phantomjs的方法: 参照:http://www.cnblogs.com/lgh344902118/p/6369054.html a.去https://bitbucket ...

  3. 遍历DOM树,获取子节点

    获取子节点的方法有:  方法  说明  children()  选取子节点,可以带过滤参数.但只能选择子节点,不能选择孙子节点.  find()  选取子节点,可以带过滤参数.可以选择子节点及孙子节点 ...

  4. [Apache]网站页面静态化与Apache调优(图)

    ---------------------------------------------------------------------------------------------------- ...

  5. Apache Mina UDP连接目标服务器地址时出现异常

    俩种情形,第一种是开始连接时候就没连上服务器:第二种是服务器关闭连接,出现的异常: 第一种: java.lang.reflect.InvocationTargetException at sun.re ...

  6. log4j 文件配置

    //log4j配置日志文件输出到磁盘一天一个 log4j.appender.File=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.F ...

  7. 解决idea控制台乱码及项目乱码

    如果控制台出现乱码,解决办法: 第1方案:.找到安装idea的路径下找idea文件下的bin中vmoptions文件,打开该文件,加上-Dfile.encoding=UTF-8 第二方案: 第3种方案 ...

  8. Numpy知识(三)

    ndarray的花式索引. 正负数索引,正数就是从0开始的下标正向寻找,负数是-1开始的负向寻找. arr[[1,5,2,6],[0,3,1,2]]:拿取arr[1,0],arr[5,3],arr[2 ...

  9. HTTP协议(Requset、Response)

    目录 http协议 http报文解析: Http请求(浏览器->服务器) HttpServletRequest对象: Http响应(服务器->浏览器) HttpServletRespons ...

  10. STO单没有取进FP,IN_SAELS_ORDER表无,但IN_PO_STO有

    描述 :业务反馈STO单没有取进FP,经检查IN_SALES_ORDER表没有此单数据,但在IN_PO_STO表却有 跟进如下: 1.检查IN_PO_STO表是否有数据 '; 2.检查SAP_SALE ...