C++ LRU cache 实现

目录

  • LRU
  • 问题
  • 实现

LRU

简单回顾 LRU( Least Recently Used),最近最久未使用。
LRU 缓存要具备以下特点:

  • 新增缓存时,应该被放到 Cache 的最前面
  • 访问某个缓存之后,也应该被挪到 Cache 的最前面
  • 容量不够,擦除尾端的Cache

最近翻了下mediapipe的源码,发现里面有个image_multi_pool.cc,基本原理就是使用LRU cache 对image对象池的管理,不过里面LRU实现用的是deque+unordered_map。
主要代码

class ImageMultiPool {public:ImageMultiPool() {}explicit ImageMultiPool(void* ignored) {}~ImageMultiPool();// Obtains a buffer. May either be reused or created anew.Image GetBuffer(int width, int height, bool use_gpu,ImageFormat::Format format /*= ImageFormat::SRGBA*/){IBufferSpec key(width, height, format);auto pool_it = pools_cpu_.find(key);if (pool_it == pools_cpu_.end()) {// Discard the least recently used pool in LRU cache.if (pools_cpu_.size() >= kMaxPoolCount) {auto old_spec = buffer_specs_cpu_.front();  // Front has LRU.buffer_specs_cpu_.pop_front();pools_cpu_.erase(old_spec);}buffer_specs_cpu_.push_back(key);  // Push new spec to back.std::tie(pool_it, std::ignore) = pools_cpu_.emplace(std::piecewise_construct, std::forward_as_tuple(key),std::forward_as_tuple(MakeSimplePoolCpu(key)));} else {// Find and move current 'key' spec to back, keeping others in same order.auto specs_it = buffer_specs_cpu_.begin();while (specs_it != buffer_specs_cpu_.end()) {if (*specs_it == key) {buffer_specs_cpu_.erase(specs_it);break;}++specs_it;}buffer_specs_cpu_.push_back(key);}return GetBufferFromSimplePool(pool_it->first, pool_it->second);}struct IBufferSpec {IBufferSpec(int w, int h, mediapipe::ImageFormat::Format f): width(w), height(h), format(f) {}int width;int height;mediapipe::ImageFormat::Format format;};private:std::unordered_map<IBufferSpec, SimplePoolcpu, IBufferSpecHash> pools_cpu_std::deque<IBufferSpec> buffer_specs_cpu_;
};

问题

对LRU管理对象池,没问题,但是使用deque实现LRU管理最近使用的池感觉不太合适,里面的遍历deque查找最近使用的池也不是最优解。

实现

其实就是把deque用list代替,list 元素插删可以保证o(1),deque只保证头尾插删的大部分情况下O(1)复杂度,触发resize时还是要做整体迁移O(n)。
另外一个就是存储迭代器,方便擦除LRU ,这个也是不能使用deque的原因,插入和擦除都可能会导致deque的迭代器失效,而list则只有在删除元素时,该元素的迭代器失效。

#include <iostream>
#include <unordered_map>
#include <list>
#include <mutex>
#include <thread>template <typename KeyType, typename ValueType, int capacity = 10>
class LRUCache {private:std::unordered_map<KeyType, std::pair<ValueType, typename std::list<KeyType>::iterator>> cache;std::list<KeyType> lruList;std::mutex mtx;  // Mutex for synchronizationpublic:ValueType get(const KeyType& key) {std::lock_guard<std::mutex> lock(mtx);  // Lock for thread safetyif (cache.find(key) != cache.end()) {// Move the accessed item to the front of the listlruList.erase(cache[key].second);lruList.push_front(key);cache[key].second = lruList.begin();return cache[key].first;}return ValueType();  // Return a default-constructed value if the key is not in the cache}void put(const KeyType& key, const ValueType& value) {std::lock_guard<std::mutex> lock(mtx);  // Lock for thread safetyif (cache.find(key) != cache.end()) {// If key exists, update its value and move to the frontcache[key].first = value;lruList.erase(cache[key].second);lruList.push_front(key);cache[key].second = lruList.begin();} else {// If key does not existif (cache.size() >= capacity) {// Remove the least recently used itemKeyType lruKey = lruList.back();cache.erase(lruKey);lruList.pop_back();}// Add the new key-value pairlruList.push_front(key);cache[key] = std::make_pair(value, lruList.begin());}}friend std::ostream& operator<<(std::ostream& os,const LRUCache<KeyType, ValueType, capacity>& rhs) {for (auto p : rhs.lruList) {os << p << " ";}return os;}
};int main() {LRUCache<std::string, int, 2> cache;  // Capacity is set to 2std::thread t1([&]() {cache.put("one", 1);cache.put("two", 2);std::cout << "Thread 1 cache: " << cache << std::endl;std::cout << "Thread 1: " << cache.get("one") << std::endl;std::cout << "Thread 1 cache: " << cache << std::endl;});std::thread t2([&]() {cache.put("three", 3);std::cout << "Thread 2 cache: " << cache << std::endl;std::cout << "Thread 2: " << cache.get("two") << std::endl;std::cout << "Thread 2 cache: " << cache << std::endl;std::cout << "Thread 2: " << cache.get("one") << std::endl;std::cout << "Thread 2 cache: " << cache << std::endl;});t1.join();t2.join();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/72507.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt5中connect信号槽无效问题 C++

在写QT的组件信号槽时遇到一个问题&#xff0c;我的QspinBox组件用connect连接函数总是无效&#xff0c;解决办法是&#xff1a; 在QT5中推荐使用如下形式连接槽函数&#xff1a; QObject::connect(ui->spinBox,QOverload<int>::of(&QSpinBox::valueChanged),th…

Java--日志管理

日志管理 作用&#xff1a; 设置日志级别&#xff0c;决定什么日志信息应该被输出、什么日志信息应该被忽略。 基本工具 见的日志管理用具有:JDK logging&#xff08;配置文件&#xff1a;logging.properties&#xff09; 和log4j(配置文件&#xff1a;log4j.properties) 。…

联合教育部高等学校科学研究发展中心,阿依瓦科技创新教育专项正式发布!

7 月 24 日&#xff0c;教育部科技发展中心官网发布了《中国高校产学研创新基金&#xff0d;阿依瓦科技创新教育专项申请指南》。 针对高校在人工智能、智能制造、智慧校园、大数据等领域科研和教研的创新研究&#xff0c;教育部高等学校科学研究发展中心与阿依瓦(北京)技术有…

Android 自定义View之圆形进度条

很多场景下都用到这种进度条&#xff0c;有的还带动画效果&#xff0c; 今天我也来写一个。 写之前先拆解下它的组成&#xff1a; 底层圆形上层弧形中间文字 那我们要做的就是&#xff1a; 绘制底层圆形&#xff1b;在同位置绘制上层弧形&#xff0c;但颜色不同&#xff…

2651. 计算列车到站时间

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;数学 知识回忆除法运算 写在最后 Tag 【数学】 题目来源 2651. 计算列车到站时间 题目解读 给你一个列车预计到达时间点和一个列车延误的时间&#xff0c;请返回列车实际的到达时间。 解题思路 方法一&#xff1a;数…

C语言每日一练--Day(16)

本专栏为c语言练习专栏&#xff0c;适合刚刚学完c语言的初学者。本专栏每天会不定时更新&#xff0c;通过每天练习&#xff0c;进一步对c语言的重难点知识进行更深入的学习。 今日练习题关键字&#xff1a;寻找奇数 峰值 二分查找 &#x1f493;博主csdn个人主页&#xff1a;小…

Spire.xls+excel文件实现单据打印

报表和单据打印&#xff0c;通常都是使用fastreport之类的&#xff0c;因为有了现成的xls模板样式&#xff0c;如果转成fastreport那还需要花时间&#xff0c;是用spire.xls这个玩意简单&#xff0c;超好用。 一.引用 using Spire.Xls; 二.基本的操作 // 创建工作簿&#xff…

C# 基础面试题(万字)

1.选择题 1. 简述下面选项能够捕获运算溢出的异常类型的有 &#xff1f; A)Exception B)SystemException C)ArithmeticException D)OverflowException 试题回答&#xff1a;AD 2. 程序员可使用&#xff08;&#xff09;语句以程序方式引发异常 &#xff1f; A)run B)try C)th…

Java 写入文件内容

1. FileOutputStream 写入文字内容到.txt文件中 package pb.io.fileoutputstream;import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;/*** 写入文件内容* author TerryZhong**/ public class InFile {public static void m…

jframe生成柱状图片+图片垂直合并+钉钉机器人推送

需求&#xff1a; 后端根据数据自动生成2个图片&#xff0c;然后把两张图片合并成一张图片&#xff0c;再发到钉钉群里&#xff0c;涉及到定时生成和推送&#xff0c;当时我们测试同事说他们写定时脚本放到服务器上&#xff0c;然后让我提供生成图片的方法和钉钉机器人的逻辑 天…

【计算机网络】UDP协议详解

目录 前言 端口号的拓展 端口号范围划分 netstat pidof UDP协议 UDP协议端格式 UDP的特点 面向数据报 UDP的缓冲区 UDP使用注意事项 基于UDP的应用层协议 前言 我们前面讲完了http和https协议&#xff0c;它们都属于应用层&#xff0c;按照TCP/IP五层模…

【Python程序设计】 项目的最佳实践【03/8】

一、说明 我们涵盖了 9 个最佳实践和示例&#xff0c;帮助您构建项目以实现协作和生产力。 以下文章是有关 Python 数据工程系列文章的一部分&#xff0c;旨在帮助数据工程师、数据科学家、数据分析师、机器学习工程师或其他刚接触 Python 的人掌握基础知识。迄今为止&#xff…

2023国赛数学建模C题模型代码

C题代码全部都完成了&#xff0c;可以看文末名片 我们先看C题的一个背景 在生鲜商超中,蔬菜类商品保鲜期短,且品相会随销售时间增加而变差。商超需要根据历史销售和需求每天进行补货。由于蔬菜品种众多、产地不同,补货时间在凌晨,商家须在不明确具体单品和价格的情况下进行补…

如何排查网站及APP数据泄露的源头

近年来数据泄露安全事件频发&#xff0c;在今年的hw网络安全攻防演练中&#xff0c;获取敏感信息、数据泄露等漏洞的得分也越来越高&#xff0c;我们SINE安全近十年来成功的帮助了许多客户&#xff0c;查找到了数据泄露的原因&#xff0c;在这里向大家分享我们的经验与心得&…

端口已被占用

报的错误 Exception in thread "Thread-76" java.net.BindException: Address already in use: bindat sun.nio.ch.Net.bind0(Native Method)at sun.nio.ch.Net.bind(Net.java:433)at sun.nio.ch.Net.bind(Net.java:425)at sun.nio.ch.ServerSocketChannelImpl.bind…

实相融、云启未来,智慧公厕让城市生活更美好

现代社会&#xff0c;随着科技的不断发展&#xff0c;人们对于城市生活的要求也在不断提升。在这个过程中&#xff0c;智慧公厕作为城市基础设施中的重要组成部分&#xff0c;正在发挥着越来越重要的作用。通过数字化、云管理、人工智能等未来的科技方式&#xff0c;智慧公厕为…

Acwing算法心得——街灯(差分)

大家好&#xff0c;我是晴天学长&#xff0c;差分广泛用于一段范围的加减运算&#xff0c;可以优化时间复杂度&#xff0c;需要的小伙伴请自取哦&#xff01;如果觉得写的不错的话&#xff0c;可以点个关注哦&#xff0c;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1…

审计智能合约的成本是多少?如何审计智能合约?

审计智能合约的成本是多少&#xff1f;如何审计智能合约&#xff1f; 智能合约安全审计在去中心化金融 (DeFi) 生态系统中非常普遍。如果您投资了一个区块链项目&#xff0c;您的决定可能部分基于智能合约代码审查的结果。 虽然大多数人都了解审计对网络安全的重要性&#xff…

计及电池储能寿命损耗的微电网经济调度(matlab代码)

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《考虑寿命损耗的微网电池储能容量优化配置》模型&#xff0c;以购售电成本、燃料成本和储能寿命损耗成本三者之和为目标函数&#xff0c;创新考虑储能寿命损耗约束、放电深度约束和储能循环次…

为什么零基础选择语言首选python

在众多编程语言中&#xff0c;似乎已经没有什么能够阻挡Python的步伐。本月Python又是第一名&#xff0c;市场份额达到了13.42%&#xff0c;在2023年&#xff0c;Python已经连续7个月蝉联榜首&#xff0c;遥遥领先于其他对手。 每个月榜单发布后&#xff0c;都有小伙伴会好奇&…