最近在工作中需要用到LRU cache用作缓存来提高性能,经过查阅各种资料,了解了其运行的机制,如下:
LRU cache可以用于在内存中保持当前的热点数据,下面实现一个有大小限制的lru cache,相关如下:
1. 模板化;
2. 利用std::unordered_map实现o(1)查找,利用std::list实现o(1)删除 (双链表+hash表);
3. 用map保持key和结点在链表中的位置(iterator)
4. 需要同时考虑如下情况:
put操作:
(1) 如果当前key存在,则将对于的结点剪切到链表的头部,同时更新哈希表中value的值;
(2) 如果当前key不存在于hash表中,且元素个数已经达到最大值,则删除链表的最后一个结点,同时把新结点插入到链表的头部,同时更新hash表(增加新节点和删除旧结点表项);
get操作:
(1)检查当前hash表中是否有该key,如果存在,则将该key对应的结点move到list的头部,并同步获取map的value;
(2)如果hash表中不存在该key,则返回false;
主要的代码如下:
void put(const key_t& key, const value_t& value) {
if (cache_items_map_.count(key) > 0) { // find the key
list_iterator_t iter = cache_items_map_[key];
iter->second = value;
cache_items_list_.splice(cache_items_list_.begin(), cache_items_list_, iter); // move to header
} else {
if (cache_items_list_.size() >= max_size_) {
cache_items_map_.erase(cache_items_list_.back().first); // remove the last element from list
cache_items_list_.pop_back(); // remove the last element in list
}
//insert new element to map and list
cache_items_list_.push_front(key_value_pair_t(key, value));
cache_items_map_[key] = cache_items_list_.begin();
}
}
bool get(const key_t& key, value_t& value) {
map_iterator_t it = cache_items_map_.find(key);
if (it == cache_items_map_.end()) {
return false;
} else {
cache_items_list_.splice(cache_items_list_.begin(), cache_items_list_, it->second);
value = it->second->second;
return true;
}
}
std::list<key_value_pair_t> cache_items_list_;
boost::unordered_map<key_t, list_iterator_t> cache_items_map_;
int64_t max_size_;
经过测试,达到了预期的结果。