`
kangkang203
  • 浏览: 13900 次
  • 性别: 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/

分享到:
评论

相关推荐

    (源码)基于C++的多线程LRU缓存系统.zip

    项目参考了LevelDB的LRU缓存设计,并在此基础上进行了优化,采用了数组形式存储元信息,并尝试实现无锁化技术,以提升系统性能。 ## 项目的主要特性和功能 1. 多线程支持系统能够支持多线程并发读写操作,确保在高...

    Go-一个简单高效用于go的LRU缓存包

    LRU(Least Recently Used)缓存策略是一种常用的内存管理策略,它通过淘汰最近最少使用的数据来保持缓存容量。在Go语言中,有许多库...同时,学习和研究开源的LRU缓存库也有助于提升我们的Go编程技巧和系统设计能力。

    python-LRU缓存.zip

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

    实现了LRU算法的缓存

    如果这个LRU缓存设计为多线程安全,那么需要考虑同步控制。可以使用`synchronized`关键字或者`java.util.concurrent`包中的工具,如`ConcurrentHashMap`来实现线程安全的缓存操作。 6. **性能优化**: - 使用`...

    Java实现LRU缓存机制:深入解析与高效编码实践

    在Java中实现LRU缓存机制,不仅可以帮助我们更好地理解和应用数据结构,还能在实际开发中提高程序的性能。本文将详细介绍如何在Java中实现LRU缓存机制,包括其原理、实现方式以及编码实践。 LRU缓存机制是一种非常...

    quicklru简单的最近最少使用LRU缓存

    在JavaScript开发中,LRU缓存可以帮助优化性能,尤其是在处理大量数据时,通过保留最近最常使用的数据而舍弃不常用的数据。 标题中的"quicklru简单的最近最少使用LRU缓存"指的是一种轻量级的LRU实现,旨在提供高效...

    LRU_缓存策略_LRU_缓存.zip

    1. LRU缓存类的设计和实现,包括如何使用哈希表和链表组合实现数据结构。 2. 插入、删除、查找和更新操作的逻辑,特别是如何在数据访问后更新数据的使用顺序。 3. 淘汰策略的实现,即如何确定并移除最近最少使用的...

    Lru缓存代码

    LRU(Least Recently Used)缓存是一种常用的内存管理策略,用于在有限的内存空间中...通过对这些代码的学习和理解,开发者可以掌握如何设计和实现自己的LRU缓存系统,从而在实际项目中应用这一高效的内存管理策略。

    2-LRU缓存1

    LRU缓存是一种常见的缓存淘汰策略,全称为“最近最少使用”。它的核心思想是,当缓存空间有限,无法存放所有数据时,优先淘汰最近最少使用的数据。LRU策略在许多系统中都有应用,特别是在数据库系统、操作系统以及...

    设计LRU缓存结构Python实现

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

    c语言实现LRU缓存.zip

    C语言实现LRU缓存涉及到数据结构的设计、哈希表和链表的应用,以及高效的内存管理。以下是对这个主题的详细讲解: 1. **LRU算法原理**: LRU算法基于“最近使用频率越高,将来越可能再次被使用”的假设。在缓存中...

    swift-SPTPersistentCache一个LRU缓存管理框架

    **Swift-SPTPersistentCache:一个高效且灵活的LRU缓存管理框架** 在iOS和macOS应用开发中,缓存管理是性能优化的关键部分。它能够帮助减少网络请求,提高用户体验,尤其是在处理大量数据或者频繁访问同一资源时。`...

    详解Java实现LRU缓存

    Java 中实现 LRU 缓存有多种方法,包括使用 LinkedHashMap 和自己设计数据结构。使用 LinkedHashMap 实现 LRU 缓存是最简单的方法,因为 LinkedHashMap 自身已经实现了顺序存储,默认情况下是按照元素的添加顺序存储...

    06丨链表(上):如何实现LRU缓存淘汰算法?1

    "链表数据结构与LRU缓存淘汰算法" 链表是一种基础的数据结构,它广泛应用于软件开发和硬件设计中。今天我们将讨论如何使用链表来实现LRU缓存淘汰算法。 首先,让我们来讨论缓存的概念。缓存是一种提高数据读取性能...

    LRU 缓存机制.docx

    在Python版本的LRU缓存实现中,类`LRUCache`包括以下关键部分: 1. 初始化方法`__init__`: 接收一个参数`capacity`,表示缓存的最大容量。创建一个字典`cache`用于存储键值对,一个列表`keys`用于存储键的顺序,...

    python-leetcode面试题解之第146题LRU缓存-题解.zip

    LeetCode第146题名为"LRU缓存",其核心任务是设计一个数据结构,该数据结构支持以下操作: 1. `put(key, value)`:如果`key`不存在,则插入键值对;如果`key`已经存在,则更新其对应的`value`。 2. `get(key)`:...

    java-leetcode题解之第146题LRU缓存.zip

    在Java编程中,实现LRU缓存通常涉及数据结构的设计,如使用HashMap和LinkedList。下面将详细探讨第146题LRU缓存的解题思路、实现方法以及相关的Java知识。 首先,我们要理解LRU缓存的工作原理。当新数据进入缓存时...

    146-LRU缓存.py

    146_LRU缓存.py

    js-leetcode题解之LRU缓存-题解.zip

    总的来说,LRU缓存策略是优化性能的有效工具,通过合理设计的数据结构和算法,我们可以用JavaScript轻松实现。LeetCode上的这道题就是很好的实践机会,帮助开发者深入理解LRU机制及其在实际问题中的应用。通过解析...

Global site tag (gtag.js) - Google Analytics