使用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语言基本构成要素:标识符.关键字.字面量. ...
随机推荐
- ReactiveX 学习笔记(2)创建数据流
操作符(Operators) Rx 的操作符能够操作(创建/转换/组合) Observable. Creating Observables 本文主题为创建/生成 Observable 的操作符. 这里 ...
- [CI]CodeIgniter特性 & 结构
------------------------------------------------------------------------------------------------- 市场 ...
- Delphi XE3通过ADOConnection 连接 MySQL 5.5.27 数据库
Delphi XE3通过ADOConnection 连接 MySQL 5.5.27 数据库 unit Unit1; interface uses Winapi.Windows, Winapi.Mess ...
- Android 抓取LOG的几种命令【转】
通常调试时候需要抓取log信息,下面几种通过ADB命令来抓取log的方法: USB连接上手机,手机需要其他操作:然后运行ADB工具:输入不同的命令即可抓取对应的LOG信息. 抓取radio LOG信息 ...
- Python基础学习Day2
一.格式化输出 需求格式化输出:姓名.年龄.工作.爱好 # 格式化输出 name = input('请输入用户名:') age = input('请输入年龄:') job = input('请输入你的 ...
- python爬取酒店信息练习
爬取酒店信息,首先知道要用到那些库.本次使用request库区获取网页,使用bs4来解析网页,使用selenium来进行模拟浏览. 本次要爬取的美团网的蚌埠酒店信息及其评价.爬取的网址为“http:/ ...
- 从后台获取的数据渲染到页面中的dom操作
很多情况下页面dom都是从后台拼接字符串添加生成的新的dom元素,在编辑器中不能看到,只能通过检查看到页面的dom结构,但是这时候会发生一个问题,就是如果使用jQuery无法进行dom操作,事件和方法 ...
- hive 踩坑
1. create tabl metastore.MetaStoreDirectSql: Self-test query [select "DB_ID" from "DB ...
- Springboot 静态资源
说下默认映射的文件夹有: classpath:/META-INF/resources classpath:/resources classpath:/static classpath:/public ...
- Java用户输入数值,做简单的猜数字游戏,导入基础的工具包util
Java用户输入数值,做简单的猜数字游戏,导入基础的工具包util,导入包的方法为,import java.util.*: 完整的实例代码: /* 导入基础工具包 */ import java.uti ...