LRU算法简介
LRU是什么?
按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常注明的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景。
1.2:小王的困惑
当小王看到LRU的时候,瞬间感觉抓住了救命稻草,这个算法不是就完全契合产品的需求吗?只要把用户数据按照LRU去筛选,利用数据结构完成的事情,完全减少了自己存储、添加字段判断、排序的过程,这样对于提高服务器性能肯定有很大的帮助,岂不美哉!小王考虑好之后,就决定先写一个demo来实现LRU,那么在php中是如何实现LRU呢?考虑了许久。以上内容来自互联网 直接 上代码
<?php
require_once('PHPUnit/Autoload.php');
require_once(dirname(__FILE__).'/../src/LRUCache/LRUCache.php'); class LRUCacheTest extends PHPUnit_Framework_TestCase { public function testStartsEmpty() {
$lru = new \LRUCache\LRUCache(1000);
$this->assertNull($lru->get(1));
} public function testGet() {
$lru = new \LRUCache\LRUCache(1000);
$key = 'key1';
$data = 'content for key1';
$lru->put($key, $data);
$this->assertEquals($lru->get($key), $data);
} public function testMultipleGet() {
$lru = new \LRUCache\LRUCache(1000);
$key = 'key1';
$data = 'content for key1';
$key2 = 'key2';
$data2 = 'content for key2'; $lru->put($key, $data);
$lru->put($key2, $data2); $this->assertEquals($lru->get($key), $data);
$this->assertEquals($lru->get($key2), $data2);
} public function testPut() {
$numEntries = 1000;
$lru = new \LRUCache\LRUCache($numEntries); $key1 = 'mykey1';
$value1 = 'myvaluefromkey1'; $lru->put($key1, $value1);
$this->assertEquals($lru->get($key1), $value1);
} public function testMassivePut() {
$numEntries = 90000;
$lru = new \LRUCache\LRUCache($numEntries); while($numEntries > 0) {
$lru->put($numEntries - 899999, 'some value...');
$numEntries--;
}
} public function testRemove() {
$numEntries = 3;
$lru = new \LRUCache\LRUCache($numEntries); $lru->put('key1', 'value1');
$lru->put('key2', 'value2');
$lru->put('key3', 'value3'); $ret = $lru->remove('key2');
$this->assertTrue($ret); $this->assertNull($lru->get('key2')); // test remove of already removed key
$ret = $lru->remove('key2');
$this->assertFalse($ret); // make sure no side effects took place
$this->assertEquals($lru->get('key1'), 'value1');
$this->assertEquals($lru->get('key3'), 'value3');
} public function testPutWhenFull() {
$lru = new \LRUCache\LRUCache(3); $key1 = 'key1';
$value1 = 'value1forkey1';
$key2 = 'key2';
$value2 = 'value2forkey2';
$key3 = 'key3';
$value3 = 'value3forkey3';
$key4 = 'key4';
$value4 = 'value4forkey4'; // fill the cache
$lru->put($key1, $value1);
$lru->put($key2, $value2);
$lru->put($key3, $value3); // access some elements more often
$lru->get($key2);
$lru->get($key2);
$lru->get($key3); // put a new entry to force cache to discard the oldest
$lru->put($key4, $value4); $this->assertNull($lru->get($key1));
}
}
<?php namespace LRUCache; /**
* Class that implements the concept of an LRU Cache
* using an associative array as a naive hashmap, and a doubly linked list
* to control the access and insertion order.
*
* @author Rogério Vicente
* @license MIT (see the LICENSE file for details)
*/
class LRUCache { // object Node representing the head of the list
private $head; // object Node representing the tail of the list
private $tail; // int the max number of elements the cache supports
private $capacity; // Array representing a naive hashmap (TODO needs to pass the key through a hash function)
private $hashmap; /**
* @param int $capacity the max number of elements the cache allows
*/
public function __construct($capacity) {
$this->capacity = $capacity;
$this->hashmap = array();
$this->head = new Node(null, null);
$this->tail = new Node(null, null); $this->head->setNext($this->tail);
$this->tail->setPrevious($this->head);
} /**
* Get an element with the given key
* @param string $key the key of the element to be retrieved
* @return mixed the content of the element to be retrieved
*/
public function get($key) { if (!isset($this->hashmap[$key])) { return null; } $node = $this->hashmap[$key];
if (count($this->hashmap) == 1) { return $node->getData(); } // refresh the access
$this->detach($node);
$this->attach($this->head, $node); return $node->getData();
} /**
* Inserts a new element into the cache
* @param string $key the key of the new element
* @param string $data the content of the new element
* @return boolean true on success, false if cache has zero capacity
*/
public function put($key, $data) {
if ($this->capacity <= 0) { return false; }
if (isset($this->hashmap[$key]) && !empty($this->hashmap[$key])) {
$node = $this->hashmap[$key];
// update data
$this->detach($node);
$this->attach($this->head, $node);
$node->setData($data);
}
else {
$node = new Node($key, $data);
$this->hashmap[$key] = $node;
$this->attach($this->head, $node); // check if cache is full
if (count($this->hashmap) > $this->capacity) {
// we're full, remove the tail
$nodeToRemove = $this->tail->getPrevious();
$this->detach($nodeToRemove);
unset($this->hashmap[$nodeToRemove->getKey()]);
}
}
return true;
} /**
* Removes a key from the cache
* @param string $key key to remove
* @return bool true if removed, false if not found
*/
public function remove($key) {
if (!isset($this->hashmap[$key])) { return false; }
$nodeToRemove = $this->hashmap[$key];
$this->detach($nodeToRemove);
unset($this->hashmap[$nodeToRemove->getKey()]);
return true;
} /**
* Adds a node to the head of the list
* @param Node $head the node object that represents the head of the list
* @param Node $node the node to move to the head of the list
*/
private function attach($head, $node) {
$node->setPrevious($head);
$node->setNext($head->getNext());
$node->getNext()->setPrevious($node);
$node->getPrevious()->setNext($node);
} /**
* Removes a node from the list
* @param Node $node the node to remove from the list
*/
private function detach($node) {
$node->getPrevious()->setNext($node->getNext());
$node->getNext()->setPrevious($node->getPrevious());
} } /**
* Class that represents a node in a doubly linked list
*/
class Node { /**
* the key of the node, this might seem reduntant,
* but without this duplication, we don't have a fast way
* to retrieve the key of a node when we wan't to remove it
* from the hashmap.
*/
private $key; // the content of the node
private $data; // the next node
private $next; // the previous node
private $previous; /**
* @param string $key the key of the node
* @param string $data the content of the node
*/
public function __construct($key, $data) {
$this->key = $key;
$this->data = $data;
} /**
* Sets a new value for the node data
* @param string the new content of the node
*/
public function setData($data) {
$this->data = $data;
} /**
* Sets a node as the next node
* @param Node $next the next node
*/
public function setNext($next) {
$this->next = $next;
} /**
* Sets a node as the previous node
* @param Node $previous the previous node
*/
public function setPrevious($previous) {
$this->previous = $previous;
} /**
* Returns the node key
* @return string the key of the node
*/
public function getKey() {
return $this->key;
} /**
* Returns the node data
* @return mixed the content of the node
*/
public function getData() {
return $this->data;
} /**
* Returns the next node
* @return Node the next node of the node
*/
public function getNext() {
return $this->next;
} /**
* Returns the previous node
* @return Node the previous node of the node
*/
public function getPrevious() {
return $this->previous;
} }
以上代码仅供大家参考
LRU算法简介的更多相关文章
- Java实现LRU算法
一.LRU算法简介 LRU(Least Recently Used)最近最久未使用算法 常见应用场景:内存管理中的页面置换算法.缓存淘汰中的淘汰策略等 二.实现理论 底层结构:双向链表 + HashM ...
- mysql 原理 ~ LRU 算法与buffer_pool
一 简介:针对查询和事务的页在内存中的处理,是如何进行的 二 LRU算法 普通 : 实现的是末尾淘汰法,当整个链表已满时,淘汰尾部,将新的数据页加入头部 mysql_lru改进 : 分为两部分 yan ...
- Guava---缓存之LRU算法
随笔 - 169 文章 - 0 评论 - 292 GuavaCache学习笔记一:自定义LRU算法的缓存实现 前言 今天在看GuavaCache缓存相关的源码,这里想到先自己手动实现一个LRU ...
- LRU算法介绍和在JAVA的实现及源码分析
一.写随笔的原因:最近准备去朋友公司面试,他说让我看一下LRU算法,就此整理一下,方便以后的复习. 二.具体的内容: 1.简介: LRU是Least Recently Used的缩写,即最近最少使用. ...
- Android图片缓存之Lru算法
前言: 上篇我们总结了Bitmap的处理,同时对比了各种处理的效率以及对内存占用大小.我们得知一个应用如果使用大量图片就会导致OOM(out of memory),那该如何处理才能近可能的降低oom发 ...
- 缓存淘汰算法--LRU算法
1. LRU1.1. 原理 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是"如果数据最近被访问过,那么将来被访问的几率也 ...
- 借助LinkedHashMap实现基于LRU算法缓存
一.LRU算法介绍 LRU(Least Recently Used)最近最少使用算法,是用在操作系统中的页面置换算法,因为内存空间是有限的,不可能把所有东西都放进来,所以就必须要有所取舍,我们应该把什 ...
- LinkedHashMap实现LRU算法
LinkedHashMap特别有意思,它不仅仅是在HashMap上增加Entry的双向链接,它更能借助此特性实现保证Iterator迭代按照插入顺序(以insert模式创建LinkedHashMap) ...
- LinkedHashMap 和 LRU算法实现
个人觉得LinkedHashMap 存在的意义就是为了实现 LRU 算法. public class LinkedHashMap<K,V> extends HashMap<K,V&g ...
随机推荐
- HTTPie 工具使用入门
HTTPie 是一个 HTTP 的命令行客户端,目标是让 CLI 和 web 服务之间的交互尽可能的人性化.这个工具提供了简洁的 http 命令,允许通过自然的语法发送任意 HTTP 请求数据,展示色 ...
- gitlab 配置.ssh实现免密登陆
首次配置gitlab的.ssh时 安装gitbash 通过gitbash 配置.ssh 打开gitbash,输入如下命令生成ssh,邮箱换成自己的 ssh-keygen -t rsa -C " ...
- 基于OVS命令的VLAN实现
利用mininet创建如下拓扑,要求支持OpenFlow 1.3协议,主机名.交换机名以及端口对应正确 直接在Open vSwitch下发流表,实现如下连通性要求 h1 -- h4互通 h2 -- h ...
- Java的Lambda表达式
Java的Lambda表达式 1. 什么是Lambda表达式 简单的说,Lambda表达式就是匿名方法.Lambda表达式让程序员能够使用更加简洁的代码,但是同样也使代码的可读性比较差. Lambda ...
- 重读APUE(2)-read返回值少于要求读取字节数
返回值: 成功返回读到的字节数,如果达到文件尾,则返回0:注意:如果有数据第一次读取会返回全部读到的字节数,下一次读取才会返回0: 出错返回-1: 返回值少于要求读取字节数的情况: 1. 读取普通文件 ...
- jQuery源码解读----part 2
分离构造器 通过new操作符构建一个对象,一般经过四步: A.创建一个新对象 B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象) C.执行构造函数中的代码 D.返回这个新对象 最后一点 ...
- SQL-W3School-高级:SQL ALIAS(别名)
ylbtech-SQL-W3School-高级:SQL ALIAS(别名) 1.返回顶部 1. 通过使用 SQL,可以为列名称和表名称指定别名(Alias). SQL Alias 表的 SQL Ali ...
- @Autowired注解与@Resource注解的区别与用法
Spring不但支持自己定义的@Autowired注解,还支持JSR-250规范定义的几个注解.如:@Resource.@PostConstruct及@PreDestroy 1. @Autowired ...
- git服务器搭建---便签做备注
今天,简单搭建了一下git服务器.发现一篇文章写的挺好的 http://www.cnblogs.com/trying/archive/2012/06/28/2863758.html 并简单和廖雪峰的结 ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_17.RabbitMQ研究-与springboot整合-消费者代码
创建消费者的类 使用@Component把这个类标记成一个Bean 把生产者里面创建的配置文件类复制过来 在原始的消费的方法上面 ,我们是可以拿到channel通道的 message.getBody就 ...