使用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();
}
使用go语言的list实现一个简单的LRU缓存的更多相关文章
- C语言中如何写一个简单可移植而又足够随机的随机数生成器
在C语言中标准库中的随机数产生函数的返回可能不是最优的,因为有些随机数生成器的低位并不随机,而另一些返回随机数的函数实现上又太复杂鸟.所以rand()%N并不是一个好方法,牛人给出的建议是使用: ra ...
- 一个简单的带缓存http代理
眼下1.0版模型非常easy.即对客户机发来的请求进行简单处理后,转发到server.转发之前先检查本地缓存.假设有.则直接回送给客户本地资源 程序流程大致例如以下图: 缓存是通过把文件保存到磁盘上, ...
- 搭建一个简单的dns缓存服务器
环境:linux 软件:bind97,bind97-utils, bind97-libs ip:192.168.192.130:192.168.192.131 -------------------- ...
- C#简单实现LRU缓存
最近跟同学吃饭扯淡的时候,由技术扯到薪资,又由薪资扯到他找工作时跟面试官是怎么扯淡拿高工资的,各种技术一顿侃,总之只要啥都了解就没问题了.谈到缓存的时候,我试探性的问了问- -你还记得LRU怎么写吗, ...
- Golang校招简历项目-简单的分布式缓存
前言 前段时间,校招投了golang岗位,但是没什么好的项目往简历上写,于是参考了许多网上资料,做了一个简单的分布式缓存项目. 现在闲下来了,打算整理下. github项目地址:https://git ...
- 为什么C语言在2013年仍然很重要:一个简单的例子
附注:在最初的文章里,我没说明进行模2^64的计算——我当然明白那些不是“正确的”斐波那契数列,其实我不是想分析大数,我只是想探寻编译器产生的代码和计算机体系结构而已. 最近,我一直在开发Dynvm— ...
- 一个简单的C语言程序(详解)
C Primer Plus之一个简单的C语言程序(详解) #include <stdio.h> int main(void) //一个简单的 C程序 { int num; //定义一个名为 ...
- 用C语言编写一个简单的词法分析程序
问题描述: 用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表.如果产生词法错误,则显示错误信息.位置,并试图从错误中恢复.简单的恢复方法 ...
- 用Go语言实现一个简单的聊天机器人
一.介绍 目的:使用Go语言写一个简单的聊天机器人,复习整合Go语言的语法和基础知识. 软件环境:Go1.9,Goland 2018.1.5. 二.回顾 Go语言基本构成要素:标识符.关键字.字面量. ...
随机推荐
- vmware搭建lnmp环境配置域名
找到nginx配置文件,修改server_name 然后找到/etc/hosts文件 修改成如下 之后在Windows本地的C盘的hosts文件中添加解析 好了,这样就可以访问了 通往牛逼的路上,在意 ...
- 使用AutoMapper时Expression的转换
此文章为转载:http://www.bubuko.com/infodetail-699735.html 参考链接: http://q.cnblogs.com/q/34480/ dudu有回复,其中 ...
- SQL语句中LEFT JOIN、JOIN、INNER JOIN、RIGHT JOIN的区别?
w3school的一套sql教程: http://www.w3school.com.cn/sql/index.asp left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录.r ...
- matlab 画二维图与三维图
二维图 ezplot('sin(x)');%默认范围 ezplot('sin(x)',[-4 4]);%自己设定范围 三维图 ezmesh('x*x+y*y');%默认范围
- iview 表单验证
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- 创建java项目思路
一.搭建 1.创建搭建项目 2.创建分层 二.理解项目(理清总体思路) 1.是否有共同部分(过滤或者拦截) 常用量 (static) 2.搭建单表基本增(是否需要返回值) 删(条件) 查(条 ...
- 四、API使用参考
官方文档:https://docs.blender.org/api/blender_python_api_current/info_api_reference.html Blender有很多互连数据类 ...
- LeetCode解题思路
刷完题后,看一下其他人的solution,受益匪浅. 可以按不同的topic刷题,比如数组.字符串.集合.链表等等.先做十道数组的题,接着再做十道链表的题. 刷题,最主要的是,学习思路. 多刷几遍.挑 ...
- java多线程与并发笔记
0.多线程,主要用来提高程序效率,处理耗时的操作. 多个线程写在同一个类里调用,并不是说写在前面的线程就会先运行.各个线程会进行争抢,能抢到系统资源的才会先运行. 因此,同一个程序,多个线程运行,可能 ...
- WAS 与IHS集成问题
1.安装好WAS与IHS后 发布Web发现无法启动 查阅资料后发现缺少插件Plugins 于是去下载安装对应版本的Plugins 发现还是有问题 后来想起发布web01时,插件还未安装.因此重新发布一 ...