• LRU算法简介


    LRU是什么?

    按照英文的直接原义就是Least Recently Used,最近最久未使用法,它是按照一个非常注明的计算机操作系统基础理论得来的:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。基于这个思想,会存在一种缓存淘汰机制,每次从内存中找到最久未使用的数据然后置换出来,从而存入新的数据!它的主要衡量指标是使用的时间,附加指标是使用的次数。在计算机中大量使用了这个机制,它的合理性在于优先筛选热点数据,所谓热点数据,就是最近最多使用的数据!因为,利用LRU我们可以解决很多实际开发中的问题,并且很符合业务场景。

    1.2:小王的困惑

       当小王看到LRU的时候,瞬间感觉抓住了救命稻草,这个算法不是就完全契合产品的需求吗?只要把用户数据按照LRU去筛选,利用数据结构完成的事情,完全减少了自己存储、添加字段判断、排序的过程,这样对于提高服务器性能肯定有很大的帮助,岂不美哉!小王考虑好之后,就决定先写一个demo来实现LRU,那么在php中是如何实现LRU呢?考虑了许久。以上内容来自互联网 直接 上代码

      1 <?php
      2 require_once('PHPUnit/Autoload.php');
      3 require_once(dirname(__FILE__).'/../src/LRUCache/LRUCache.php');
      4 
      5 class LRUCacheTest extends PHPUnit_Framework_TestCase {
      6 
      7     public function testStartsEmpty() {
      8         $lru = new LRUCacheLRUCache(1000);
      9         $this->assertNull($lru->get(1));
     10     }
     11 
     12     public function testGet() {
     13         $lru = new LRUCacheLRUCache(1000);
     14         $key = 'key1';
     15         $data = 'content for key1';
     16         $lru->put($key, $data);
     17         $this->assertEquals($lru->get($key), $data);
     18     }
     19 
     20     public function testMultipleGet() {
     21         $lru = new LRUCacheLRUCache(1000);
     22         $key = 'key1';
     23         $data = 'content for key1';
     24         $key2 = 'key2';
     25         $data2 = 'content for key2';
     26 
     27         $lru->put($key, $data);
     28         $lru->put($key2, $data2);
     29 
     30         $this->assertEquals($lru->get($key), $data);
     31         $this->assertEquals($lru->get($key2), $data2);
     32     }
     33 
     34     public function testPut() {
     35         $numEntries = 1000;
     36         $lru = new LRUCacheLRUCache($numEntries);
     37 
     38         $key1 = 'mykey1';
     39         $value1 = 'myvaluefromkey1';
     40 
     41         $lru->put($key1, $value1);
     42         $this->assertEquals($lru->get($key1), $value1);
     43     }
     44 
     45     public function testMassivePut() {
     46         $numEntries = 90000;
     47         $lru = new LRUCacheLRUCache($numEntries);
     48 
     49         while($numEntries > 0) {
     50             $lru->put($numEntries - 899999, 'some value...');
     51             $numEntries--;
     52         }
     53     }
     54 
     55     public function testRemove() {
     56         $numEntries = 3;
     57         $lru = new LRUCacheLRUCache($numEntries);
     58 
     59         $lru->put('key1', 'value1');
     60         $lru->put('key2', 'value2');
     61         $lru->put('key3', 'value3');
     62 
     63         $ret = $lru->remove('key2');
     64         $this->assertTrue($ret);
     65 
     66         $this->assertNull($lru->get('key2'));
     67 
     68         // test remove of already removed key
     69         $ret = $lru->remove('key2');
     70         $this->assertFalse($ret);
     71 
     72         // make sure no side effects took place
     73         $this->assertEquals($lru->get('key1'), 'value1');
     74         $this->assertEquals($lru->get('key3'), 'value3');
     75     }
     76 
     77     public function testPutWhenFull() {
     78         $lru = new LRUCacheLRUCache(3);
     79 
     80         $key1 = 'key1';
     81         $value1 = 'value1forkey1';
     82         $key2 = 'key2';
     83         $value2 = 'value2forkey2';
     84         $key3 = 'key3';
     85         $value3 = 'value3forkey3';
     86         $key4 = 'key4';
     87         $value4 = 'value4forkey4';
     88 
     89         // fill the cache
     90         $lru->put($key1, $value1);
     91         $lru->put($key2, $value2);
     92         $lru->put($key3, $value3);
     93 
     94         // access some elements more often
     95         $lru->get($key2);
     96         $lru->get($key2);
     97         $lru->get($key3);
     98 
     99         // put a new entry to force cache to discard the oldest
    100         $lru->put($key4, $value4);
    101 
    102         $this->assertNull($lru->get($key1));
    103     }
    104 }
      1 <?php
      2 
      3 namespace LRUCache;
      4 
      5 /**
      6  * Class that implements the concept of an LRU Cache
      7  * using an associative array as a naive hashmap, and a doubly linked list
      8  * to control the access and insertion order.
      9  *
     10  * @author Rogério Vicente
     11  * @license MIT (see the LICENSE file for details)
     12  */
     13 class LRUCache {
     14 
     15     // object Node representing the head of the list
     16     private $head;
     17 
     18     // object Node representing the tail of the list
     19     private $tail;
     20 
     21     // int the max number of elements the cache supports
     22     private $capacity;
     23 
     24     // Array representing a naive hashmap (TODO needs to pass the key through a hash function)
     25     private $hashmap;
     26 
     27     /**
     28      * @param int $capacity the max number of elements the cache allows
     29      */
     30     public function __construct($capacity) {
     31         $this->capacity = $capacity;
     32         $this->hashmap = array();
     33         $this->head = new Node(null, null);
     34         $this->tail = new Node(null, null);
     35 
     36         $this->head->setNext($this->tail);
     37         $this->tail->setPrevious($this->head);
     38     }
     39 
     40     /**
     41      * Get an element with the given key
     42      * @param string $key the key of the element to be retrieved
     43      * @return mixed the content of the element to be retrieved
     44      */
     45     public function get($key) {
     46 
     47         if (!isset($this->hashmap[$key])) { return null; }
     48 
     49         $node = $this->hashmap[$key];
     50         if (count($this->hashmap) == 1) { return $node->getData(); }
     51 
     52         // refresh the access
     53         $this->detach($node);
     54         $this->attach($this->head, $node);
     55 
     56         return $node->getData();
     57     }
     58 
     59     /**
     60      * Inserts a new element into the cache 
     61      * @param string $key the key of the new element
     62      * @param string $data the content of the new element
     63      * @return boolean true on success, false if cache has zero capacity
     64      */
     65     public function put($key, $data) {
     66         if ($this->capacity <= 0) { return false; }
     67         if (isset($this->hashmap[$key]) && !empty($this->hashmap[$key])) {
     68             $node = $this->hashmap[$key];
     69             // update data
     70             $this->detach($node);
     71             $this->attach($this->head, $node);
     72             $node->setData($data);
     73         }
     74         else {
     75             $node = new Node($key, $data);
     76             $this->hashmap[$key] = $node;
     77             $this->attach($this->head, $node);
     78 
     79             // check if cache is full
     80             if (count($this->hashmap) > $this->capacity) {
     81                 // we're full, remove the tail
     82                 $nodeToRemove = $this->tail->getPrevious();
     83                 $this->detach($nodeToRemove);
     84                 unset($this->hashmap[$nodeToRemove->getKey()]);
     85             }
     86         }
     87         return true;
     88     }
     89 
     90     /**
     91      * Removes a key from the cache
     92      * @param string $key key to remove
     93      * @return bool true if removed, false if not found
     94      */
     95      public function remove($key) {
     96        if (!isset($this->hashmap[$key])) { return false; }
     97        $nodeToRemove = $this->hashmap[$key];
     98        $this->detach($nodeToRemove);
     99        unset($this->hashmap[$nodeToRemove->getKey()]);
    100        return true;
    101      }
    102 
    103     /**
    104      * Adds a node to the head of the list
    105      * @param Node $head the node object that represents the head of the list
    106      * @param Node $node the node to move to the head of the list
    107      */
    108     private function attach($head, $node) {
    109         $node->setPrevious($head);
    110         $node->setNext($head->getNext());
    111         $node->getNext()->setPrevious($node);
    112         $node->getPrevious()->setNext($node);
    113     }
    114 
    115     /**
    116      * Removes a node from the list
    117      * @param Node $node the node to remove from the list
    118      */
    119     private function detach($node) {
    120         $node->getPrevious()->setNext($node->getNext());
    121         $node->getNext()->setPrevious($node->getPrevious());
    122     }
    123 
    124 }
    125 
    126 /**
    127  * Class that represents a node in a doubly linked list
    128  */
    129 class Node {
    130 
    131     /**
    132      * the key of the node, this might seem reduntant,
    133      * but without this duplication, we don't have a fast way
    134      * to retrieve the key of a node when we wan't to remove it
    135      * from the hashmap.
    136      */
    137     private $key;
    138 
    139     // the content of the node
    140     private $data;
    141 
    142     // the next node
    143     private $next;
    144 
    145     // the previous node
    146     private $previous;
    147 
    148     /**
    149      * @param string $key the key of the node
    150      * @param string $data the content of the node
    151      */
    152     public function __construct($key, $data) {
    153         $this->key = $key;
    154         $this->data = $data;
    155     }
    156 
    157     /**
    158      * Sets a new value for the node data
    159      * @param string the new content of the node
    160      */
    161     public function setData($data) {
    162         $this->data = $data;
    163     }
    164 
    165     /**
    166      * Sets a node as the next node
    167      * @param Node $next the next node
    168      */
    169     public function setNext($next) {
    170         $this->next = $next;
    171     }
    172 
    173     /**
    174      * Sets a node as the previous node
    175      * @param Node $previous the previous node
    176      */
    177     public function setPrevious($previous) {
    178         $this->previous = $previous;
    179     }
    180 
    181     /**
    182      * Returns the node key
    183      * @return string the key of the node
    184      */
    185     public function getKey() {
    186         return $this->key;
    187     }
    188 
    189     /**
    190      * Returns the node data
    191      * @return mixed the content of the node
    192      */
    193     public function getData() {
    194         return $this->data;
    195     }
    196 
    197     /**
    198      * Returns the next node
    199      * @return Node the next node of the node
    200      */
    201     public function getNext() {
    202         return $this->next;
    203     }
    204 
    205     /**
    206      * Returns the previous node
    207      * @return Node the previous node of the node
    208      */
    209     public function getPrevious() {
    210         return $this->previous;
    211     }
    212 
    213 }

    以上代码仅供大家参考

  • 相关阅读:
    AO中的GraphicsLayer---------元素的容器
    Spring中基于Java的配置@Configuration和@Bean用法
    spring注解开发AnnotationConfigApplicationContext的使用
    java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "getClassLoader")
    java.lang.ClassNotFoundException: org.apache.juli.logging.LogFactory的解决办法
    Multiple markers at this line @Override的解决方法
    springmvc-mvc:resource标签使用
    SpringMVC <mvc:view-controller path=""/>标签
    深入理解Spring MVC 思想
    解决 Eclipse 导入项目后 Maven Dependencies missing jar 问题
  • 原文地址:https://www.cnblogs.com/phpxj/p/11637295.html
Copyright © 2020-2023  润新知