`
kangkang203
  • 浏览: 13370 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

LRU缓存设计

阅读更多

参考 http://blog.csdn.net/ryfdizuo/article/details/7916996

 

缓存的数据结构采用哈希表,key到value的映射。

网上有些资料采用记录数据的使用时刻 实现LRU策略,此处采用双向链表 实现LRU策略。LRU Least Recently Used,MRU Most Recently Used

双向链表,lruPtr头指向最近最少使用的元素,mruPtr头指向最近最多使用的元素。

LRUCache<int, int> tc(3);  //最大三个元素
tc.insert(1, 101);
tc.insert(2, 102);
tc.insert(3, 103);

最终存储结构如下图:

哈希表中的元素:

  • 黄色是 key域,哈希的键
  • 蓝色是value域,存储的数据值
  • 红色是newerPtr 域,指向下一个更新的 哈希项
  • 绿色是oldPtr域,指向前一个更旧的 哈希项
LRUCache缓存中 保存mruPtr和lruPtr,缓存的查找、更新元素 首先从hash_table中发起,然后同步更新到双向链表中。

lru.hpp

  1. /* 
  2. * Implementation of an LRU cache with a maximum size. 
  3. * 
  4. * See http://code.google.com/p/lru-cache-cpp/ for usage and limitations. 
  5. * 
  6. * Licensed under the GNU LGPL: http://www.gnu.org/copyleft/lesser.html 
  7. * 
  8. * Pierre-Luc Brunelle, 2011 
  9. * pierre-luc.brunelle@polytml.ca 
  10. * 
  11. * 使用stl中的map替换hash_table 
  12. * Peteryfren China, 2012 
  13. */  
  14.   
  15. #include <map>  
  16. #include <sstream>  
  17. #include <cassert>  
  18.   
  19. namespace lru{  
  20.   
  21.     //-------------------------------------------------------------  
  22.     // Bucket  
  23.     //-------------------------------------------------------------  
  24.   
  25.     template<class K, class V>  
  26.     struct LRUCacheH4Value  
  27.     {  
  28.         typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;  
  29.   
  30.         LRUCacheH4Value()  
  31.             : _v(), _older(NULL), _newer(NULL) { }  
  32.   
  33.         LRUCacheH4Value(const V & v, Val * older, Val * newer)  
  34.             : _v(v), _older(older), _newer(newer) { }   
  35.   
  36.         V _v;  
  37.         Val * _older;  
  38.         Val * _newer;  
  39.     };  
  40.   
  41.   
  42.     //-------------------------------------------------------------  
  43.     // Const Iterator  
  44.     //-------------------------------------------------------------  
  45.   
  46.     template<class K, class V>  
  47.     class LRUCacheH4ConstIterator  
  48.     {  
  49.     public:  
  50.         typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;  
  51.         typedef LRUCacheH4ConstIterator<K, V> const_iterator;  
  52.         typedef Val & reference;  
  53.         typedef Val * pointer;  
  54.   
  55.         enum DIRECTION {  
  56.             MRU_TO_LRU = 0,  
  57.             LRU_TO_MRU  
  58.         };  
  59.   
  60.         LRUCacheH4ConstIterator(const Val * ptr = NULL, DIRECTION dir = MRU_TO_LRU);  
  61.   
  62.         const_iterator & operator++();  
  63.         const_iterator operator++(int);  
  64.   
  65.         bool operator==(const const_iterator & other);  
  66.         bool operator!=(const const_iterator & other);  
  67.   
  68.         const K & key() const;  
  69.         const V & value() const;  
  70.   
  71.     private:  
  72.         const Val * _ptr;  
  73.         DIRECTION _dir;  
  74.     };  
  75.   
  76.   
  77.     template<class K, class V>  
  78.     LRUCacheH4ConstIterator<K, V>::LRUCacheH4ConstIterator(  
  79.         const typename LRUCacheH4ConstIterator<K, V>::Val * ptr,  
  80.         typename LRUCacheH4ConstIterator<K, V>::DIRECTION dir)  
  81.         : _ptr(ptr), _dir(dir)  
  82.     {  
  83.     }  
  84.   
  85.   
  86.     template<class K, class V>  
  87.     LRUCacheH4ConstIterator<K, V> & LRUCacheH4ConstIterator<K, V>::operator++()  
  88.     {  
  89.         assert(_ptr);  
  90.         _ptr = (_dir == LRUCacheH4ConstIterator<K, V>::MRU_TO_LRU ? _ptr->second._older : _ptr->second._newer);  
  91.         return *this;  
  92.     }  
  93.   
  94.   
  95.     template<class K, class V>  
  96.     LRUCacheH4ConstIterator<K, V> LRUCacheH4ConstIterator<K, V>::operator++(int)  
  97.     {  
  98.         const_iterator ret = *this;  
  99.         ++*this;  
  100.         return ret;  
  101.     }  
  102.   
  103.   
  104.     template<class K, class V>  
  105.     bool LRUCacheH4ConstIterator<K, V>::operator==(const const_iterator & other)  
  106.     {  
  107.         return _ptr == other._ptr;  
  108.     }  
  109.   
  110.   
  111.     template<class K, class V>  
  112.     bool LRUCacheH4ConstIterator<K, V>::operator!=(const const_iterator & other)  
  113.     {  
  114.         return _ptr != other._ptr;  
  115.     }  
  116.   
  117.   
  118.     template<class K, class V>  
  119.     const K & LRUCacheH4ConstIterator<K, V>::key() const  
  120.     {  
  121.         assert(_ptr);  
  122.         return _ptr->first;  
  123.     }  
  124.   
  125.   
  126.     template<class K, class V>  
  127.     const V & LRUCacheH4ConstIterator<K, V>::value() const  
  128.     {  
  129.         assert(_ptr);   
  130.         return _ptr->second._v;  
  131.     }  
  132.   
  133.   
  134. // file scope  
  135.   
  136.   
  137. namespace lru {  
  138.   
  139.     //-------------------------------------------------------------  
  140.     // LRU Cache  
  141.     //-------------------------------------------------------------  
  142.   
  143.     template<class K, class V>  
  144.     class LRUCacheH4  
  145.     {  
  146.     public:  
  147.         typedef LRUCacheH4ConstIterator<K, V> const_iterator;  
  148.   
  149.     public:  
  150.         LRUCacheH4(int maxsize);                    // Pre-condition: maxsize >= 1  
  151.         LRUCacheH4(const LRUCacheH4 & other);  
  152.         ~LRUCacheH4() { _map.clear(); }  
  153.   
  154.         V & operator[](const K & key);  
  155.         void insert(const K & key, const V & value);  
  156.   
  157.         int size() const;  
  158.         int maxsize() const;  
  159.         bool empty() const;  
  160.   
  161.         const_iterator find(const K & key);         // updates the MRU  
  162.         const_iterator find(const K & key) const;   // does not update the MRU  
  163.         const_iterator mru_begin() const;           // from MRU to LRU  
  164.         const_iterator lru_begin() const;           // from LRU to MRU  
  165.         const_iterator end() const;  
  166.   
  167.         void dump_mru_to_lru(std::ostream & os) const;  
  168.   
  169.     private:  
  170.         typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;  
  171.   
  172.         typedef std::map<K, LRUCacheH4Value<K,V> > MAP_TYPE;  
  173.   
  174.     private:  
  175.         Val * _update_or_insert(const K & key);  
  176.         Val * _update(typename MAP_TYPE::iterator it);  
  177.         Val * _insert(const K & key);  
  178.   
  179.     private:  
  180.         MAP_TYPE _map;  
  181.         Val * _mru;  
  182.         Val * _lru;  
  183.         int _maxsize;  
  184.     };  
  185.   
  186.   
  187.     // Reserve enough space to avoid resizing later on and thus invalidate iterators  
  188.     template<class K, class V>  
  189.     LRUCacheH4<K, V>::LRUCacheH4(int maxsize)  
  190.         : _mru(NULL),  
  191.         _lru(NULL),  
  192.         _maxsize(maxsize)  
  193.     {  
  194.         if (_maxsize <= 0)  
  195.             throw "LRUCacheH4: expecting cache size >= 1";  
  196.     }  
  197.   
  198.   
  199.     template<class K, class V>  
  200.     LRUCacheH4<K, V>::LRUCacheH4(const LRUCacheH4<K, V> & other)  
  201.         : _maxsize(other._maxsize),  
  202.         _mru(NULL),  
  203.         _lru(NULL)  
  204.     {  
  205.         for (const_iterator it = other.lru_begin();  it != other.end();  ++it)  
  206.             this->insert(it.key(), it.value());  
  207.     }  
  208.   
  209.   
  210.     template<class K, class V>  
  211.     V & LRUCacheH4<K, V>::operator[](const K & key)  
  212.     {  
  213.         return _update_or_insert(key)->second._v;  
  214.     }  
  215.   
  216.   
  217.     template<class K, class V>  
  218.     void LRUCacheH4<K, V>::insert(const K & key, const V & value)  
  219.     {  
  220.         _update_or_insert(key)->second._v = value;  
  221.     }  
  222.   
  223.   
  224.     template<class K, class V>  
  225.     int LRUCacheH4<K, V>::size() const  
  226.     {  
  227.         return _map.size();  
  228.     }  
  229.   
  230.   
  231.     template<class K, class V>  
  232.     int LRUCacheH4<K, V>::maxsize() const   
  233.     {  
  234.         return _maxsize;  
  235.     }  
  236.   
  237.   
  238.     template<class K, class V>  
  239.     bool LRUCacheH4<K, V>::empty() const  
  240.     {  
  241.         return size() > 0;  
  242.     }  
  243.   
  244.   
  245.     // updates MRU  
  246.     template<class K, class V>  
  247.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::find(const K & key)  
  248.     {  
  249.         typename MAP_TYPE::iterator it = _map.find(key);  
  250.   
  251.         if (it != _map.end())  
  252.             return const_iterator(_update(it), const_iterator::MRU_TO_LRU);  
  253.         else  
  254.             return end();  
  255.     }  
  256.   
  257.   
  258.     // does not update MRU  
  259.     template<class K, class V>  
  260.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::find(const K & key) const  
  261.     {  
  262.         typename MAP_TYPE::iterator it = _map.find(key);  
  263.   
  264.         if (it != _map.end())  
  265.             return const_iterator(&*it, const_iterator::MRU_TO_LRU);  
  266.         else  
  267.             return end();  
  268.     }  
  269.   
  270.   
  271.     template<class K, class V>  
  272.     void LRUCacheH4<K, V>::dump_mru_to_lru(std::ostream & os) const  
  273.     {  
  274.         os << "LRUCacheH4(" << size() << "/" << maxsize() << "): MRU --> LRU: " << std::endl;  
  275.         for (const_iterator it = mru_begin();  it != end();  ++it)  
  276.             os << it.key() << ": " << it.value() << std::endl;  
  277.     }  
  278.   
  279.   
  280.     template<class K, class V>  
  281.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::mru_begin() const  
  282.     {  
  283.         return const_iterator(_mru, const_iterator::MRU_TO_LRU);  
  284.     }  
  285.   
  286.   
  287.     template<class K, class V>  
  288.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::lru_begin() const  
  289.     {  
  290.         return const_iterator(_lru, const_iterator::LRU_TO_MRU);  
  291.     }  
  292.   
  293.   
  294.     template<class K, class V>  
  295.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::end() const  
  296.     {  
  297.         return const_iterator();  
  298.     }  
  299.   
  300.   
  301.     template<class K, class V>  
  302.     typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_update_or_insert(const K & key)  
  303.     {  
  304.         typename MAP_TYPE::iterator it = _map.find(key);  
  305.         if (it != _map.end())  
  306.             return _update(it);  
  307.         else  
  308.             return _insert(key);  
  309.     }  
  310.   
  311.   
  312.     template<class K, class V>  
  313.     typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_update(typename MAP_TYPE::iterator it)  
  314.     {  
  315.         LRUCacheH4Value<K, V> & v = it->second;  
  316.         Val * older = v._older;  
  317.         Val * newer = v._newer;  
  318.         Val * moved = &*it;  
  319.   
  320.         // possibly update the LRU  
  321.         if (moved == _lru && _lru->second._newer)  
  322.             _lru = _lru->second._newer;  
  323.   
  324.         if (moved != _mru) {  
  325.             // "remove" key from current position  
  326.             if (older)  
  327.                 older->second._newer = newer;  
  328.             if (newer)  
  329.                 newer->second._older = older;  
  330.   
  331.             // "insert" key to MRU position  
  332.             v._older = _mru;  
  333.             v._newer = NULL;  
  334.             _mru->second._newer = moved;  
  335.             _mru = moved;  
  336.         }  
  337.   
  338.         return moved;  
  339.     }  
  340.   
  341.   
  342.     template<class K, class V>  
  343.     typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_insert(const K & key)  
  344.     {  
  345.         // if we have grown too large, remove LRU  
  346.         if (_map.size() >= _maxsize) {  
  347.             Val * old_lru = _lru;  
  348.             if (_lru->second._newer) {  
  349.                 _lru = _lru->second._newer;  
  350.                 _lru->second._older = NULL;  
  351.             }  
  352.             _map.erase(old_lru->first);  
  353.         }  
  354.   
  355.         // insert key to MRU position  
  356.         std::pair<typename MAP_TYPE::iterator, bool> ret  
  357.             = _map.insert( Val(key, LRUCacheH4Value<K, V>(V(), _mru, NULL)) );  
  358.   
  359.         Val * inserted = &*ret.first;  
  360.         if (_mru)  
  361.             _mru->second._newer = inserted;  
  362.         _mru = inserted;  
  363.   
  364.         // possibly update the LRU  
  365.         if (!_lru)  
  366.             _lru = _mru;  
  367.         else if (!_lru->second._newer)  
  368.             _lru->second._newer = _mru;  
  369.   
  370.         return inserted;  
  371.     }  
  372.   
  373.   
  374. }  // namespace lru  


测试代码:

  1. #include <iostream>  
  2.   
  3. #include "lru.hpp"  
  4.   
  5. using namespace lru;  
  6. using namespace std;  
  7.   
  8. int main()  
  9. {  
  10.     typedef LRUCacheH4<intint> CacheType;  
  11.   
  12.     CacheType tc(3);  
  13.   
  14.     tc.insert(1, 101);  
  15.     tc.insert(2, 102);  
  16.     tc.insert(3, 103);  
  17.       
  18.     tc.insert(2, 1002);  
  19.   
  20.     cout << tc[1] << endl;  
  21.   
  22.     cout << "================" << endl;  
  23.   
  24.     for (CacheType::const_iterator it = tc.mru_begin();  it != tc.end();  ++it)  
  25.         cout << it.key() << " " << it.value() << endl;  
  26.   
  27.     cout << "================" << endl;  
  28.   
  29.     for (CacheType::const_iterator it = tc.lru_begin();  it != tc.end();  ++it)  
  30.         cout << it.key() << " " << it.value() << endl;  
  31.   
  32.     system("PAUSE");  
  33.     return 0;  
  34. }  

参考:

1. High-Throughput, Thread-Safe, LRU Caching
http://www.ebaytechblog.com/2011/08/30/high-throughput-thread-safe-lru-caching/

分享到:
评论

相关推荐

    python-LRU缓存.zip

    “Python—LRU缓存.zip”是一个压缩文件,其中包含了使用Python实现的最近最少使用...缓存系统设计者:LRU缓存算法在缓存系统设计中有着广泛的应用,这个资源可以为缓存系统设计者提供实现和优化缓存策略的思路。

    设计LRU缓存结构Python实现

    设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能: 1. Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存 2. get(key):如果关键字 ...

    146-LRU缓存.py

    146_LRU缓存.py

    lrucacheleetcode-Leetcode-LRU-cache:146.LRU缓存

    lru缓存leetcode Leetcode-LRU-cache LRU缓存 设计和实现最近最少使用 (LRU) 缓存的数据结构。 它应该支持以下操作:get 和 put。 get(key) - 如果键存在于缓存中,则获取键的值(将始终为正),否则返回 -1。 put...

    lrucacheleetcode-lru-cache:设计和实现最近最少使用(LRU)缓存的数据结构(在Scala中)

    lru缓存leetcode LRU缓存 看问题- 设计和实现最近最少使用 (LRU) 缓存的数据结构。 它应该支持以下操作:get 和 put。 get(key) - 如果键存在于缓存中,则获取键的值(将始终为正),否则返回 -1。 put(key, value) ...

    rectcircle#course-design-DBMS#2-LRU缓存1

    这种机制称为缓存LRU算法:最近最少使用算法当缓存没有满时,新插入的数据直接放入缓存当缓存满了时,删除最近最少使用的那一项,然后在将数据插入缓存缓存性能要求查询

    论文研究-盘阵列中基于分组LRU的缓存调度策略设计与实现 .pdf

    盘阵列中基于分组LRU的缓存调度策略设计与实现,张梦龙,陈俭喜,盘阵列系统由于面向多用户的访问请求,传统的缓存调度策略不能很好的发挥作用。本文提出了基于分组的LRU缓存调度优化策略,既可以

    lrucacheleetcode-go-leetcode:go-leetcode

    lru缓存leetcode go-leetcode Golang 编写的习题解答。 LRU缓存 设计和实现最近最少使用 (LRU) 缓存的数据结构。 它应该支持以下操作:get 和 put。 get(key) - 如果键存在于缓存中,则获取键的值(将始终为正),...

    Java和Android的LRU缓存及实现原理

    Android提供了LRUCache类,可以方便的使用它来实现LRU算法的缓存。Java提供了LinkedHashMap,可以用该类很方便的实现LRU算法,Java的LRULinkedHashMap就是直接继承了LinkedHashMap,进行了极少的改动后就可以实现LRU...

    rush:LRU缓存可快速处理繁忙的应用程序

    LRU缓存可快速处理繁忙的应用程序。 Rush设计用于具有高异步并发性的应用程序获取和访问数据。 如果您希望对从外部资源中获取的数据进行快速的内存中缓存,这将非常有用。 当您想从某处获取数据时,使用rush.get...

    LRUCache:Java中的简单LRU缓存。 “破解编码面试”中的问题16.25

    Java中的简单LRU缓存。 “破解编码面试”中的问题16.25。 问题 设计用于Web查找的缓存机制,该机制将映射两个值,例如街道地址和营业税率。 假定这两个值是字符串,并且缓存具有最大大小并开始为空。 当达到最大大...

    javalruleetcode-Diksha-singh:迪克沙辛格

    缓存设计并实现最近最少使用(LRU)缓存的数据结构。 它应该支持以下操作:get 和 put。 get(key) - 如果键存在于缓存中,则获取键的值(将始终为正),否则返回 -1。 put(key, value) - 如果键不存在,则设置或插入...

    lrucacheleetcode-PythonStudy:Python学习

    lru缓存leetcode 这是一个学习python的项目! #code 这是python的一些测试功能特性 #datastruct 这是一些在python中研究数据结构的代码 #leetcode 这是一些解决##Reverse Integer 整数的逆向数字问题的代码。 示例 1...

    ARM高速缓存(Cache)Verilog代码 包含ISE工程

    该工程包含数据缓存D_Cache和指令缓存I_Cache的Verilog代码和仿真文件,附带可运行的ISE工程文件,Cache的详细技术参数包含在.v文件的注释中。 直接相连16KB D_Cache Cache写策略: 写回法+写分配 (二路)组相连16KB ...

    146

    LRU缓存设计和实现最近最少使用(LRU)缓存的数据结构。 它应该支持以下操作:获取和放置。 get(key)-如果键存在于缓存中,则获取键的值(始终为正),否则返回-1。 put(key,value)-如果密钥不存在,则设置或...

    lru-cache:编程求职面试设计问题-最近最少使用的缓存

    实现一个LRU(最近最少使用)缓存。 它应该能够使用缓存大小n进行初始化,并包含以下方法: set(key, value) :将key设置为value。 如果缓存中已经有n个项目,并且我们要添加一个新项目,那么它还应该删除最近最少...

    Verilog-caches:用 Verilog-HDL 编写的各种缓存

    4way_4word 缓存4路组相联高速缓存行大小为 4 个字缓存替换策略是 LRU 8way_4word 缓存8路组相联高速缓存行大小为 4 个字缓存替换策略为 Pseudo-LRU free_config_cache 默认缓存配置为 8 路组关联您可以通过发送 ...

    python实现LRU热点缓存及原理

    LRU算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。。这篇文章主要介绍了python实现LRU热点缓存,需要的朋友可以参考下

    lrucacheleetcode-leetcode-LRU-Cache:我的leetcodeLRU缓存问题的解决方案

    lru缓存leetcode 问题描述 设计一个遵循最近最少使用 (LRU) 缓存约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity)使用正大小容量初始化 LRU 缓存。 int get(int key)如果键存在则返回键的值,否则返回-1...

    页面置换算法LRU模拟c#

    LRU页面置换算法模拟,vs2010,面向对象设计

Global site tag (gtag.js) - Google Analytics