Nodejs基于LRU算法实现的缓存处理操作示例


Posted in NodeJs onMarch 17, 2017

本文实例讲述了Nodejs基于LRU算法实现的缓存处理操作。分享给大家供大家参考,具体如下:

LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的,是根据页面调入内存后的使用情况进行决策了。由于无法预测各页面将来的使用情况,只能利用“最近的过去”作为“最近的将来”的近似,因此,LRU算法就是将最近最久未使用的页面予以淘汰。

可以用一个特殊的栈来保存当前正在使用的各个页面的页面号。当一个新的进程访问某页面时,便将该页面号压入栈顶,其他的页面号往栈底移,如果内存不够,则将栈底的页面号移除。这样,栈顶始终是最新被访问的页面的编号,而栈底则是最近最久未访问的页面的页面号。

如输入以下序列时:4,7,0,7,1,0,1,2,1,2,6

结果为:

4
4        7
4        7        0
4        0        7
4        0        7        1
4        7        1        0
4        7        0        1
4        7        0        1        2
4        7        0        2        1
4        7        0        1        2
7        0        1        2        6

适用于Node.js的一个LRU缓存,capacity为缓存容量,为0时构造一般缓存。

function CacheLRU(capacity) {
/* 利用Buffer写的一个LRU缓存,capacity为缓存容量,为0时不限容量。
myCache = new CacheLRU(capacity); //构造缓存
myCache.get(key); //读取名为key的缓存值
myCache.put(key, value); //写入名为key的缓存值
myCache.remove(key); //删除名为key的缓存值
myCache.removeAll(); //清空缓存
myCache.info(); //返回myCache缓存信息
LRU原理:对所有缓存数据的key构建hash链表,当对某一数据进行get或put操作时,将其key提到链表前端(最新)。当进行put数据超出容量时,删除链表尾端(最旧)的缓存数据。
hash链表操作可直接定位key,无需历遍整个hash对象,故读写极快。缓存容量不再影响读写速度。
*/
  this.capacity = capacity || Number.MAX_VALUE;
  this.data = {};
  this.hash = {};
  this.linkedList = {
    length: 0,
    head: null,
    end: null
  }
  if (capacity <= 0) this.capacity = Number.MAX_VALUE;
};
CacheLRU.prototype.get = function(key) {
  key = '_' + key;
  var lruEntry = this.hash[key];
  if (!lruEntry) return;
  refresh(this.linkedList, lruEntry);
  return JSON.parse(this.data[key].toString());
};
CacheLRU.prototype.put = function(key, value) {
  key = '_' + key;
  var lruEntry = this.hash[key];
  if (value === undefined) return this;
  if (!lruEntry) {
    this.hash[key] = {key: key};
    this.linkedList.length += 1;
    lruEntry = this.hash[key];
  }
  refresh(this.linkedList, lruEntry);
  this.data[key] = new Buffer(JSON.stringify(value));
  if (this.linkedList.length > this.capacity) this.remove(this.linkedList.end.key.slice(1));
  return this;
};
CacheLRU.prototype.remove = function(key) {
  key = '_' + key;
  var lruEntry = this.hash[key];
  if (!lruEntry) return this;
  if (lruEntry === this.linkedList.head) this.linkedList.head = lruEntry.p;
  if (lruEntry === this.linkedList.end) this.linkedList.end = lruEntry.n;
  link(lruEntry.n, lruEntry.p);
  delete this.hash[key];
  delete this.data[key];
  this.linkedList.length -= 1;
  return this;
};
CacheLRU.prototype.removeAll = function() {
  this.data = {};
  this.hash = {};
  this.linkedList = {
    length: 0,
    head: null,
    end: null
  }
  return this;
};
CacheLRU.prototype.info = function() {
  var size = 0,
    data = this.linkedList.head;
  while (data){
    size += this.data[data.key].length;
    data = data.p;
  }
  return {
    capacity: this.capacity,
    length: this.linkedList.length,
    size: size
  };
};
// 更新链表,把get或put方法操作的key提到链表head,即表示最新
function refresh(linkedList, entry) {
  if (entry != linkedList.head) {
    if (!linkedList.end) {
      linkedList.end = entry;
    } else if (linkedList.end == entry) {
      linkedList.end = entry.n;
    }
    link(entry.n, entry.p);
    link(entry, linkedList.head);
    linkedList.head = entry;
    linkedList.head.n = null;
  }
}
// 对两个链表对象建立链接,形成一条链
function link(nextEntry, prevEntry) {
  if (nextEntry != prevEntry) {
    if (nextEntry) nextEntry.p = prevEntry;
    if (prevEntry) prevEntry.n = nextEntry;
  }
}
module.exports = CacheLRU;
// test:
/*var user = new CacheLRU(5);
user.put('user1', {name:'admin', age: 30});
user.put('user2', {name:'user', age: 31});
user.put('user3', {name:'guest', age: 32});
user.put('user4', {name:'guest', age: 34});
user.put('user5', {name:'guest', age: 35});
console.log(user.get('user1'));
console.log(user.get('user2'));
console.log(user.get('user3'));
user.put('user6', {name:'guest', age: 36});
console.log(user.info());*/

LRU算法也可以用于一些实际的应用中,如你要做一个浏览器,或类似于淘宝客户端的应用的就要用到这个原理。大家都知道浏览器在浏览网页的时候会把下载的图片临时保存在本机的一个文件夹里,下次再访问时就会,直接从本机临时文件夹里读取。但保存图片的临时文件夹是有一定容量限制的,如果你浏览的网页太多,就会一些你最不常使用的图像删除掉,只保留最近最久使用的一些图片。这时就可以用到LRU算法 了,这时上面算法里的这个特殊的栈就不是保存页面的序号了,而是每个图片的序号或大小;所以上面这个栈的元素都用Object类来表示,这样的话这个栈就可以保存的对像了。

希望本文所述对大家nodejs程序设计有所帮助。

NodeJs 相关文章推荐
nodejs的require模块(文件模块/核心模块)及路径介绍
Jan 14 NodeJs
基于NodeJS的前后端分离的思考与实践(四)安全问题解决方案
Sep 26 NodeJs
详解nodejs微信公众号开发——4.自动回复各种消息
Apr 11 NodeJs
nodejs和C语言插入mysql数据库乱码问题的解决方法
Apr 14 NodeJs
nodejs操作mysql实现增删改查的实例
May 28 NodeJs
详解nodejs通过代理(proxy)发送http请求(request)
Sep 22 NodeJs
nodejs爬虫初试superagent和cheerio
Mar 05 NodeJs
nodejs异步编程基础之回调函数用法分析
Dec 26 NodeJs
nodejs基础之buffer缓冲区用法分析
Dec 26 NodeJs
Nodejs监听日志文件的变化的过程解析
Aug 04 NodeJs
Nodejs libuv运行原理详解
Aug 21 NodeJs
NodeJS有难度的面试题(能答对几个)
Oct 09 NodeJs
用nodeJS搭建本地文件服务器的几种方法小结
Mar 16 #NodeJs
nodejs+express实现文件上传下载管理网站
Mar 15 #NodeJs
nodejs搭建本地http服务器教程
Mar 13 #NodeJs
搭建简单的nodejs http服务器详解
Mar 09 #NodeJs
nodejs读写json文件的简单方法(必看)
Mar 09 #NodeJs
Nodejs 获取时间加手机标识的32位标识实现代码
Mar 07 #NodeJs
nodejs中全局变量的实例解析
Mar 07 #NodeJs
You might like
php expects parameter 1 to be resource, array given 错误
2011/03/23 PHP
深入mysql_fetch_row()与mysql_fetch_array()的区别详解
2013/06/05 PHP
使用PHP导出Redis数据到另一个Redis中的代码
2014/03/12 PHP
nginx+thinkphp下解决不支持pathinfo模式
2015/07/01 PHP
Laravel给生产环境添加监听事件(SQL日志监听)
2017/06/19 PHP
精解window.setTimeout()&amp;window.setInterval()使用方式与参数传递问题!
2007/11/23 Javascript
Javascript 阻止javascript事件冒泡,获取控件ID值
2009/06/27 Javascript
jQuery 表格工具集
2010/04/25 Javascript
点弹代码 点击页面任何位置都可以弹出页面效果代码
2012/09/17 Javascript
js中页面的重新加载(当前页面/上级页面)及frame或iframe元素引用介绍
2013/01/24 Javascript
JS截取url中问号后面参数的值信息
2014/04/29 Javascript
2014年最火的Node.JS后端框架推荐
2014/10/27 Javascript
JQuery操作元素的css样式
2015/03/09 Javascript
jQuery四种选择器使用及示例
2016/06/05 Javascript
JavaScript实现点击文本自动定位到下拉框选中操作
2016/06/15 Javascript
纯javascript版日历控件
2016/11/24 Javascript
bootstrap fileinput 上传插件的基础使用
2017/02/17 Javascript
mac中利用NVM管理不同node版本的方法详解
2017/11/08 Javascript
[02:11]2016国际邀请赛中国区预选赛全程回顾
2016/07/01 DOTA
python制作企业邮箱的爆破脚本
2016/10/05 Python
利用Python2下载单张图片与爬取网页图片实例代码
2017/12/25 Python
python引用(import)某个模块提示没找到对应模块的解决方法
2019/01/19 Python
Python实现的登录验证系统完整案例【基于搭建的MVC框架】
2019/04/12 Python
python numpy之np.random的随机数函数使用介绍
2019/10/06 Python
Pytorch 实现权重初始化
2019/12/31 Python
Python使用进程Process模块管理资源
2020/03/05 Python
css3实现文字首尾衔接跑马灯的示例代码
2020/10/16 HTML / CSS
森海塞尔美国官网:Sennheiser耳机与耳麦
2017/07/19 全球购物
Vero Moda西班牙官方购物网站:丹麦BESTSELLER旗下知名女装品牌
2018/04/27 全球购物
EJB3.1都有哪些改进
2012/11/17 面试题
商务英语应届生自我鉴定
2013/12/08 职场文书
乡镇办公室工作决心书
2014/03/11 职场文书
课程改革实施方案
2014/03/16 职场文书
法律专业求职信
2014/05/24 职场文书
Golang表示枚举类型的详细讲解
2021/09/04 Golang
Nginx stream 配置代理(Nginx TCP/UDP 负载均衡)
2021/11/17 Servers