"알고리즘 - LRU"

하나 : 개요

  - 관리의 LRU 캐쉬 정책 자체가 리눅스 / 레디 스 / mysql을 구현했다. 그냥 다른 구현.

  - LRU 알고리즘 [ 최근 최소 사용 (최근 최소 사용) ]

  - 역사적 데이터 레코드를 기반으로 데이터 액세스를 제거하기 위해, 핵심 아이디어는 "데이터가 최근에 방문한 된 경우, 다음 미래의 접근 가능성도 높다"입니다.

   - GitHub의

 

2 : LRU 알고리즘 구현 단일 연결리스트

  - 아이디어

    -이  단독 목록 연결 달성하기를

 

  - 프로세스

    - 1. 새로운 데이터는 연결 목록의 헤드에 삽입된다 ;

    - 2 캐시 히트마다 (즉, 데이터 캐시 액세스 처), 그 데이터가 링크 된리스트의 헤드로 이동된다 ;

    - 3. 목록이 가득 차면, 링크 된 목록 데이터의 꼬리가 삭제됩니다 .

 

  - 장점

    - 간단한.

    - 핫 데이터는 LRU 효율적있을 때.

 

  - 단점

    -  LRU가 적중률에 산발적, 정기적 인 일괄 작업은 급격한 하락으로 이어질 것입니다 , 캐시 오염은 매우 심각하다 .

    -  히트 목록이 때 통과해야하는 다음 머리에 데이터를 이동해야하는 데이터의 블록 인덱스 히트를 찾을 수 있습니다.

 

  - 흐름도

    - 

 

  - 코드 구현 (PHP)

    • / * * 
       * 아이디어 
       * 단쇄 달성 
       * 원리 
       * 단일 쇄 
       * 프로세스 
       * 1. 새로운 데이터가 연결 목록의 헤드에 삽입된다 
       * 2 캐시 히트 (즉, 캐시 데이터가 액세스 될) 데이터는리스트의 헤드로 이동 될 때마다 ; 
       목록이 가득 차면 * 3은 링크 된리스트 데이터의 꼬리는 폐기된다. 
       * 장점 
       * 간단한. 
       * 본 경우 핫 스폿 데이터는 LRU 효율적. 
       * 단점은 
       캐시 오염이 매우 심각, LRU는 적중률에 산발적,주기적인 배치 작업이 급격한 하락으로 이어질 것입니다 *. 
       히트리스트, 데이터 블록 인덱스 히트를 찾을 때 * 당신은 머리에 데이터를 이동해야하는, 통과해야합니다. 
       * / 
      클래스 LRU 
      { 
          공공  정적 $ lruList = []; // 순차 저장 단일 쇄 구조 
          공개  정적 $ MAXLEN = 5. ;   // 리스트의 최대 길이를 허용 
          공개  정적 $ nowLen = 0;   // 현재 길이 나열 
      
          / * * 
           * LRU_1 생성자.를 
           PHP가 상주 프로그램 프로세스 아니므리스트 초기화에 의해 달성 될 수 있기 때문에 *의 MySQL / 레디 스 
           * / 
          공용 기능 __construct () 
          { 
              셀프 : $ lruList = []; 
              자기 : : $ nowLen   = COUNT (셀프 : $ lruList); 
          } 
      
          / * * 
           * = 키> 값 가져 
           파라미터 : 키 $의 
           *의 @return 널 (null) 
           * / 
          공공 기능 GET (키 $)를 
          { 
              $ 값 = 널 (null) ; 
      
              // LRU 대기열이 비어, 직접 반환 
              IF (!:: $ lruList 셀프) { 
                  자기 lruList : $ [] = [키 $는 =>는 $ 은이 ->는 GetData의 (키 $)를]; // 실제 상황 데이터 항목 가져 
                  셀프 : $ nowLen ++ ;
                   반환 $ 값; 
              } 
      
              // LRU 버퍼 찾기 
              에을 ($ I = 0 ; $ 나는 자기 : $ nowLen <; $ 내가 ++ ) { 
      
                  // 캐시가 존재하는 경우, 프로세스가 직접 반환하고 목록 헤더 데이터를 다시 삽입 
                  IF (는 isset (셀프 :: lruList $ [$ I] [키 $])) { 
      
                      $ 값 = 자기 : $ lruList [$ I] [키 $] 
      
                      설정되지 않은 ($ lruList 자체 :: [$ I]); 
      
                      array_unshift (셀프 : $ lruList [주요 $ => $ 값]); 
      
                      BREAK; 
                  } 
              } 
      
      
              // 만약 어떤 캐시 LRU 
              IF (! {는 isset ($ 값)) 
      
                  // 삽입 헤드 
                  array_unshift (자체 : $ lruList, [키 $ => $ 은이 ->는 GetData의 (키 $)]); // 실제 상황에 따라 데이터 항목을 얻을 
                  자가 :: $ nowLen ++ ; 
      
                  IF (자기 : $ nowLen> 자기 MAXLEN :: $)를 { 
                      자기 nowLen : $ - ; 
                      array_pop (자체 : $ lruList); 
                  } 
              } 
      
              반환 $ 값; 
      
          } 
      
          / * * 
           * LRU 출력 큐 
           * / 
          공용  기능 echoLruList ()
          { 
              위해서 var_dump (셀프 : $ lruList); 
          } 
      
          / * * 
           * 인수 실제 환경 데이터를 기반으로 
           파라미터 : 키 $의 
           *의 @return 문자열 
           * / 
          공공 함수 GetData의 (키 $) 
          { 
              반환  ' 데이터 ' ; 
          } 
      }

       

 

세 : LRU K 알고리즘

  - 아이디어

    -하기 위해 LRU '캐시 중독'피하기 문제

    -  큐 추가 캐시의 수가 발생하는 유지하기를. 핵심 아이디어는에 대해 "최근에 사용한 한 번"의 기준을 확장하는 것입니다 "최근에 사용한 K 시간을."

 

  - 원리

    - LRU에 비해 LRU-K는 역사 큐를 유지하기 위해 더 필요한 모든 캐시 된 데이터를 기록에 액세스하고 있습니다.

    - 만 액세스 데이터의 수는 캐시에 데이터 전에 K 시간에 도달 할 때 호출됩니다.

    - 당신이 데이터를 제거해야하는 경우, LRU-K는 현재 시간에서 최대 규모의 데이터를 K 번째 액세스 시간을 제거하는 것입니다.

 

  - 프로세스

    - 1. 데이터가 처음으로 액세스는 액세스 히스토리리스트에 추가 ;

    - 2. 히스토리리스트에서의 데이터 액세스가 있다면 K 배에 도달하지 않은 소정의 규칙에 따라 액세스를 LRU가 제거 ;

    - 3. 액세스 데이터 접속 이력 큐의 개수 때 도달 K 시간은 , 데이터가 인덱스 기록 큐로부터 삭제되며 상기 버퍼 큐 데이터 버퍼 시간으로 재 정렬 데이터 버퍼 큐;

    - 4. 캐시 데이터 큐가 재정렬, 다시 액세스 할 수 있습니다;

    - 5. 데이터 버퍼 큐 행 즉, 데이터의 끝에서 단계적으로 제거해야합니다 제거 '끝에서 두 번째 K 방문을 지금부터 가장 오래된 "데이터입니다.

 

  - 장점

    - LRU-K가 발생 "캐시 오염"의 문제를 줄일 수, 적중률은 LRU보다 높다.

 

  - 단점

    -  LRU-K 큐는 우선 순위 큐, 알고리즘 복잡도이고 비용은 상대적으로 높다.

    - LRU-K는 역사적 집단을 유지하기 위해 필요한, 그래서 때문에 메모리 소비가 더있을 것입니다 .

 

  - 흐름도

    - 

 

  - 코드 구현

    • /**
       * 思路
       *     为了避免 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';
          }
      }

       

추천

출처www.cnblogs.com/25-lH/p/11121172.html