"Algorithm - Lru"

I. Overview

  - the LRU cache policy for the management , which itself has implemented in Linux / Redis / Mysql in. Just different implementations.

  - LRU algorithm [ Least recently used (Least Recently Used) ]

  - to eliminate data access based on historical data record, its core idea is "if the data has recently been visited, then the probability of future access is also higher."

   - GITHUB

 

Two: Lru algorithm implemented singly linked list

  - Ideas

    -  singly linked list to achieve

 

  - Process

    - 1. The new data is inserted into the head of the linked list ;

    - 2. Whenever a cache hit (i.e., cache data to be accessed), then the data is moved to the head of the linked list ;

    - 3. When the list is full, the tail of the linked list data is discarded .

 

  - Benefits

    - simple.

    - when there is hot data, the LRU good efficiency.

 

  - shortcomings

    -  sporadic, periodic batch operation will lead to a sharp decline in LRU hit rate , cache pollution is very serious .

    -  need to traverse when the hit list , find the data block index hit, then need to move the data to the head.

 

  - flow chart

    - 

 

  - code implementation (PHP)

    • / * * 
       * Idea 
       * achieve single chain 
       * principles 
       * single chain 
       * Process 
       * 1. The new data is inserted into the head of the linked list; 
       * 2. Whenever a cache hit (i.e., cache data to be accessed), the data is moved to the head of the list ; 
       * 3. when the list is full, the tail of the linked list data is discarded. 
       * Advantage 
       * simple. 
       * When present hotspot data, the LRU good efficiency. 
       * Shortcomings 
       * sporadic, periodic batch operation will lead to a sharp decline in LRU hit rate, cache pollution is very serious. 
       * Need to traverse when the hit list, find the data block index hit, then you need to move the data to the head. 
       * / 
      Class LRU 
      { 
          public  static $ lruList = []; // sequential storage single chain structure 
          public  static $ = maxLen . 5 ;   // list maximum length allowed 
          public  static $ nowLen = 0;   // list the current length 
      
          / * * 
           . * LRU_1 constructor 
           * Because PHP is not a resident program process, so the list can be achieved by initialization Mysql / Redis 
           * / 
          public function __construct () 
          { 
              Self :: $ lruList = []; 
              Self: : $ nowLen   = COUNT (Self :: $ lruList); 
          } 
      
          / * * 
           * = Get Key> value 
           * @param Key $ 
           * @return null 
           * / 
          public function GET (Key $) 
          { 
              $ value = null ; 
      
              // LRU the queue is empty, the direct return 
              IF (!:: $ lruList Self) { 
                  Self lruList :: $ [] = [Key $ => $ the this -> the getData (Key $)]; // Get the actual situation data item 
                  Self :: $ nowLen ++ ;
                   return $ value; 
              } 
      
              // Find lru buffer 
              for ($ I = 0 ; $ I <Self :: $ nowLen; $ I ++ ) { 
      
                  // if the cache exists, the process directly returns, and reinsert the list header data 
                  IF (isset (Self :: lruList $ [$ I] [Key $])) { 
      
                      $ value = Self :: $ lruList [$ I] [Key $]; 
      
                      the unset ($ lruList Self :: [$ I]); 
      
                      array_unshift (Self :: $ lruList , [Key $ => $ value]); 
      
                      BREAK; 
                  } 
              } 
      
      
              // If no cache lru 
              IF (! Isset ($ value)) { 
      
                  // insertion head 
                  array_unshift (Self :: $ lruList, [Key $ => $ the this -> the getData (Key $)]); // get the data items according to the actual situation 
                  Self :: $ nowLen ++ ; 
      
                  IF (Self :: $ nowLen> Self maxLen :: $) { 
                      Self nowLen :: $ - ; 
                      array_pop (Self :: $ lruList); 
                  } 
              } 
      
              return $ value; 
      
          } 
      
          / * * 
           * Lru output queue 
           * / 
          public function echoLruList () 
          {
              var_dump (Self :: $ lruList); 
          } 
      
          / * * 
           * based on real environmental data acquired 
           * @param Key $ 
           * @return String 
           * / 
          public function the getData (Key $) 
          { 
              return  ' Data ' ; 
          } 
      }

       

 

Three: Lru K algorithm

  - Ideas

    - In order to avoid the LRU 'cache poisoning' problem

    -  add a queue to maintain the number of cache arise. The core idea is to extend the "recently used one time," the criteria for the "recently used K times."

 

  - Principle

    - compared to the LRU, the LRU-K need more to maintain a queue for history being accessed recorded all cached data.

    - Only when the number of accesses data reaches K times before the data into the cache.

    - When you need to eliminate data, LRU-K would eliminate K-th access time from the current time the largest data.

 

  - Process

    - 1. Data is first accessed, added to the access history list ;

    - 2. If the data access in the history list has not reached K times access, according to certain rules LRU eliminated ;

    - 3. When the number of accesses data access history queue reached K times , the data will be deleted from the index history queue, the data to the buffer queue , the buffer and the data buffer queue re-ordered by time;

    - 4. cache data queue is accessed again, reordering;

    - 5. need to eliminate data buffer queue row phased out at the end of the data, namely: elimination "penultimate K visit from now the oldest" data.

 

  - Benefits

    - LRU-K reduces the problem of "cache pollution" caused, the hit rate is higher than the LRU.

 

  - shortcomings

    -  the LRU-K queue is a priority queue, the algorithm complexity and the cost is relatively high.

    - Since the LRU-K also need to maintain a historical cohort, so the memory consumption will be more .

 

  - flow chart

    - 

 

  - Code

    • /**
       * 思路
       *     为了避免 LRU 的 '缓存污染' 问题
       *     增加一个队列来维护缓存出现的次数。其核心思想是将“最近使用过1次”的判断标准扩展为“最近使用过K次”。
       * 原理
       *     相比LRU,LRU-K需要多维护一个队列,用于记录所有缓存数据被访问的历史。
       *     只有当数据的访问次数达到K次的时候,才将数据放入缓存。
       *     当需要淘汰数据时,LRU-K会淘汰第K次访问时间距当前时间最大的数据
       * 流程
       *     1.数据第一次被访问,加入到访问历史列表;
       *     2.如果数据在访问历史列表里后没有达到K次访问,则按照一定规则 LRU淘汰;
       *     3.当访问历史队列中的数据访问次数达到K次后,将数据索引从历史队列删除,将数据移到缓存队列中,并缓存此数据,缓存队列重新按照时间排序;
       *     4.缓存数据队列中被再次访问后,重新排序;
       *     5.需要淘汰数据时,淘汰缓存队列中排在末尾的数据,即:淘汰“倒数第K次访问离现在最久”的数据。
       * 优点
       *     LRU-K降低了“缓存污染”带来的问题,命中率比LRU要高。
       * 缺点
       *     LRU-K队列是一个优先级队列,算法复杂度和代价比较高。
       *     由于LRU-K还需要维护历史队列,所以消耗的内存会更多。
       */
      class Lru_K
      {
          public static $historyList = []; // 访问历史队列
          public static $lruList     = []; // 顺序存储单链表结构
          public static $maxLen      = 5;  // 链表允许最大长度
          public static $nowLen      = 0;  // 链表当前长度
      
          /**
           * LRU_K constructor.
           * 由于 PHP 不是常驻进程程序,所以链表初始化可以通过 Mysql/Redis 实现
           */
          public function __construct()
          {
              self::$lruList     = [];
              self::$historyList = [];
              self::$nowLen      = count(self::$lruList);
          }
      
          /**
           * 获取 key => value
           * @param $key
           * @return null
           */
          public function get($key)
          {
              $value = null;
      
              // 查找 lru 缓存
              for ($i = 0; $i < self::$nowLen; $i++) {
      
                  // 如果存在缓存,则直接返回,并将数据重新插入链表头部
                  if (isset(self::$lruList[$i][$key])) {
      
                      $value = self::$lruList[$i][$key];
      
                      unset(self::$lruList[$i]);
      
                      array_unshift(self::$lruList, [$key => $value]);
      
                      break;
                  }
              }
      
              // 如果没有找到 lru 缓存, 则进入历史队列进行计数,当次数大于等于5时候,进入缓存队列
              if (!isset($value)) {
                  self::$historyList[$key]++;
      
                  $value = $this->getData($key);
      
                  // 进入缓存队列
                  if (self::$historyList[$key] >= 5) {
                      array_unshift(self::$lruList, [$key => $value]); // 根据实际项目情况获取数据
                      self::$nowLen++;
      
                      if (self::$nowLen > self::$maxLen) {
                          self::$nowLen--;
                          array_pop(self::$lruList);
                      }
      
                      unset(self::$historyList[$key]); // 历史队列推出
                  }
              }
      
              return $value;
      
          }
      
          /**
           * 输出 Lru 队列
           */
          public function echoLruList()
          {
              var_dump(self::$lruList);
              var_dump(self::$historyList);
          }
      
          /**
           * 根据真实环境获取数据
           * @param $key
           * @return string
           */
          public function getData($key)
          {
              return 'data';
          }
      }

       

Guess you like

Origin www.cnblogs.com/25-lH/p/11121172.html