当前位置: 首页 > news >正文

实现一个 LRU 风格的缓存类

实现一个缓存类

    • 需求描述
    • 豆包
      • 解决思路:
      • 实现代码:
      • 优化1
        • 1. `std::list::remove` 的时间复杂度问题
        • 2. 代码复用
        • 优化后的代码
        • 优化说明
      • 优化2
        • 1. 边界条件检查
        • 2. 异常处理
        • 3. 代码封装性
        • 4. 线程安全
        • 优化后的代码示例
        • 优化说明
    • DeepSeek(深度思考R1):
      • 代码实现
        • 实现说明:
      • 优化方案一:基础互斥锁版本
      • 优化方案二:读写锁版本(C++17+)
      • 优化分析说明:

需求描述

类似于Windows系统的 win 菜单最近打开功能模块,使用最近最少使用(LRU)的缓存淘汰策略,缓存可以设置最大容量。
get:获取缓存数据,不存在时返回 -1
put:新增或者更新缓存,当容量已满时,删除最早的数据,再插入

class UpdateCaching {public:UpdateCaching(int capacity){}int get(int key){}void put(int key ,int value){}
}

豆包

解决思路:

  1. 使用 std::unordered_map 存储键值对,以便快速查找和更新数据。(为啥使用 unordered_map 而不是 map)

  2. 使用 std::list 存储键的访问顺序,以便在容量满时删除最早的数据。

  3. put 操作中:

    • 检查缓存是否已满,如果已满,删除 list 中的第一个元素,并从 unordered_map 中移除对应的键值对。
    • 将新元素添加到 unordered_map 中,并将键添加到 list 的末尾。
  4. get 操作中:

    • 使用 unordered_map 查找键是否存在,如果存在,将键移到 list 的末尾,表示最近访问过。

实现代码:

#include <iostream>
#include <unordered_map>
#include <list>class UpdateCaching {
private:std::unordered_map<int, int> cache;std::list<int> keyOrder;int capacity;public:UpdateCaching(int cap) : capacity(cap) {}int get(int key) {if (cache.count(key) == 0) {return -1;}// 将访问的键移到列表末尾,表示最近使用过keyOrder.remove(key);keyOrder.push_back(key);return cache[key];}void put(int key, int value) {if (cache.count(key) > 0) {// 键已存在,更新值并将其移到列表末尾cache[key] = value;keyOrder.remove(key);keyOrder.push_back(key);return;}if (cache.size() >= capacity) {// 缓存已满,移除最久未使用的元素int oldestKey = keyOrder.front();keyOrder.pop_front();cache.erase(oldestKey);}// 插入新元素cache[key] = value;keyOrder.push_back(key);}
};int main() {UpdateCaching cache(3);cache.put(1, 10);cache.put(2, 20);cache.put(3, 30);std::cout << cache.get(2) << std::endl;  // 输出 20cache.put(4, 40);  // 缓存已满,删除最早的元素 (1, 10)std::cout << cache.get(1) << std::endl;  // 输出 -1return 0;
}

优化1

1. std::list::remove 的时间复杂度问题

getput 方法中,使用 keyOrder.remove(key) 来移动元素到列表末尾。std::list::remove 的时间复杂度是 O ( n ) O(n) O(n),因为它需要遍历整个列表来找到要删除的元素。可以通过维护一个指向每个键在列表中位置的映射,将这一操作的时间复杂度优化到 O ( 1 ) O(1) O(1)

2. 代码复用

getput 方法中都有将键移到列表末尾的操作,可以将这一操作提取成一个单独的方法,提高代码的复用性。

优化后的代码
#include <iostream>
#include <unordered_map>
#include <list>class UpdateCaching {
private:std::unordered_map<int, int> cache;std::unordered_map<int, std::list<int>::iterator> keyIterators;std::list<int> keyOrder;int capacity;// 将键移到列表末尾void moveToBack(int key) {auto it = keyIterators[key];keyOrder.erase(it);keyOrder.push_back(key);keyIterators[key] = --keyOrder.end();//更新映射容器中key对应的迭代器}public:UpdateCaching(int cap) : capacity(cap) {}int get(int key) {if (cache.count(key) == 0) {return -1;}// 将访问的键移到列表末尾,表示最近使用过moveToBack(key);return cache[key];}void put(int key, int value) {if (cache.count(key) > 0) {// 键已存在,更新值并将其移到列表末尾cache[key] = value;moveToBack(key);return;}if (cache.size() >= capacity) {// 缓存已满,移除最久未使用的元素int oldestKey = keyOrder.front();keyOrder.pop_front();cache.erase(oldestKey);keyIterators.erase(oldestKey);}// 插入新元素cache[key] = value;keyOrder.push_back(key);keyIterators[key] = --keyOrder.end();}
};int main() {UpdateCaching cache(3);cache.put(1, 10);cache.put(2, 20);cache.put(3, 30);std::cout << cache.get(2) << std::endl;  // 输出 20cache.put(4, 40);  // 缓存已满,删除最早的元素 (1, 10)std::cout << cache.get(1) << std::endl;  // 输出 -1return 0;
}
优化说明
  1. 引入 keyIterators 映射:用于存储每个键在 keyOrder 列表中的迭代器,这样在移动元素到列表末尾时,就可以直接通过迭代器删除元素,时间复杂度为 O ( 1 ) O(1) O(1)
  2. 提取 moveToBack 方法:将将键移到列表末尾的操作提取成一个单独的方法,提高了代码的复用性和可读性。

通过这些优化,getput 方法的时间复杂度都可以优化到 O ( 1 ) O(1) O(1)

优化2

1. 边界条件检查

在构造函数中可以添加对 capacity 参数的检查,避免传入不合法的值(如负数),增强代码的健壮性。

2. 异常处理

在实际应用中,std::unordered_mapstd::list 的操作可能会抛出异常(如内存分配失败),可以考虑添加异常处理机制,让代码在异常情况下能有更好的表现。

3. 代码封装性

可以提供一些额外的接口方法,如获取缓存当前大小、检查缓存是否为空等,方便调用者使用。

4. 线程安全

如果该缓存类要在多线程环境下使用,需要添加同步机制,保证线程安全。

优化后的代码示例
#include <iostream>
#include <unordered_map>
#include <list>
#include <mutex>class UpdateCaching {
private:std::unordered_map<int, int> cache;std::unordered_map<int, std::list<int>::iterator> keyIterators;std::list<int> keyOrder;int capacity;mutable std::mutex mtx;  // 用于线程安全的互斥锁// 将键移到列表末尾void moveToBack(int key) {std::lock_guard<std::mutex> lock(mtx);  // 加锁,在get或put中被调用时已经加锁了,且是同一个锁 mtx,不会再次进行真正的加锁操作auto it = keyIterators[key];keyOrder.erase(it);keyOrder.push_back(key);keyIterators[key] = --keyOrder.end();}public:// 构造函数添加边界检查UpdateCaching(int cap) : capacity(cap) {if (cap <= 0) {throw std::invalid_argument("Capacity must be a positive integer.");}}int get(int key) {std::lock_guard<std::mutex> lock(mtx);  // 加锁if (cache.count(key) == 0) {return -1;}// 将访问的键移到列表末尾,表示最近使用过moveToBack(key);return cache[key];}void put(int key, int value) {std::lock_guard<std::mutex> lock(mtx);  // 加锁if (cache.count(key) > 0) {// 键已存在,更新值并将其移到列表末尾cache[key] = value;moveToBack(key);return;}if (cache.size() >= capacity) {// 缓存已满,移除最久未使用的元素int oldestKey = keyOrder.front();keyOrder.pop_front();cache.erase(oldestKey);keyIterators.erase(oldestKey);}// 插入新元素cache[key] = value;keyOrder.push_back(key);keyIterators[key] = --keyOrder.end();}// 获取缓存当前大小size_t size() const {std::lock_guard<std::mutex> lock(mtx);  // 加锁return cache.size();}// 检查缓存是否为空bool empty() const {std::lock_guard<std::mutex> lock(mtx);  // 加锁return cache.empty();}
};int main() {try {UpdateCaching cache(3);cache.put(1, 10);cache.put(2, 20);cache.put(3, 30);std::cout << cache.get(2) << std::endl;  // 输出 20cache.put(4, 40);  // 缓存已满,删除最早的元素 (1, 10)std::cout << cache.get(1) << std::endl;  // 输出 -1std::cout << "Cache size: " << cache.size() << std::endl;std::cout << "Is cache empty? " << (cache.empty() ? "Yes" : "No") << std::endl;} catch (const std::exception& e) {std::cerr << "Exception: " << e.what() << std::endl;}return 0;
}

在多线程环境下使用:

// 线程函数,用于向缓存中插入数据
void insertData(UpdateCaching& cache, int start, int end) {for (int i = start; i < end; ++i) {cache.put(i, i * 10);}
}// 线程函数,用于从缓存中获取数据
void getData(UpdateCaching& cache, int start, int end) {for (int i = start; i < end; ++i) {int value = cache.get(i);if (value != -1) {std::cout << "Key: " << i << ", Value: " << value << std::endl;}}
}int main() {try {UpdateCaching cache(10);// 创建插入数据的线程std::thread insertThread1(insertData, std::ref(cache), 0, 5);std::thread insertThread2(insertData, std::ref(cache), 5, 10);// 创建获取数据的线程std::thread getThread1(getData, std::ref(cache), 0, 5);std::thread getThread2(getData, std::ref(cache), 5, 10);// 等待所有线程完成insertThread1.join();insertThread2.join();getThread1.join();getThread2.join();std::cout << "Cache size: " << cache.size() << std::endl;} catch (const std::exception& e) {std::cerr << "Exception: " << e.what() << std::endl;}return 0;
}
优化说明
  1. 边界条件检查:在构造函数中添加了对 capacity 参数的检查,如果传入的值不合法,会抛出 std::invalid_argument 异常。
  2. 异常处理:通过 try-catch 块捕获可能抛出的异常,并进行相应的处理,提高了代码的健壮性。
  3. 代码封装性:添加了 size()empty() 方法,方便调用者获取缓存的当前大小和检查缓存是否为空。
  4. 线程安全:使用 std::mutex 实现了简单的线程安全机制,在关键操作(如 getputsizeempty 等)前加锁,确保多线程环境下的操作安全。

DeepSeek(深度思考R1):

代码实现

#include <list>
#include <unordered_map>
#include <algorithm>using namespace std;class UpdateCaching {
private:int max_capacity;list<pair<int, int>> cache_list;unordered_map<int, list<pair<int, int>>::iterator> cache_map;public:UpdateCaching(int capacity) {max_capacity = max(0, capacity); // 处理非法容量值}int get(int key) {auto it = cache_map.find(key);if (it == cache_map.end()) {return -1;}// 将访问的节点移动到链表头部cache_list.splice(cache_list.begin(), cache_list, it->second);return it->second->second;}void put(int key, int value) {if (max_capacity <= 0) return; // 容量为0时不操作auto it = cache_map.find(key);if (it != cache_map.end()) {// 更新已有值并移到头部it->second->second = value;cache_list.splice(cache_list.begin(), cache_list, it->second);return;}// 插入新数据if (cache_map.size() >= max_capacity) {// 删除最久未使用的数据int last_key = cache_list.back().first;cache_map.erase(last_key);cache_list.pop_back();}// 插入新数据到头部cache_list.emplace_front(key, value);cache_map[key] = cache_list.begin();}
};
实现说明:
  1. 数据结构选择

    • 使用双向链表list维护访问顺序,最近访问的节点保持在链表头部
    • 使用哈希表unordered_map实现O(1)时间复杂度的查找操作
  2. 核心操作

    • get操作
      • 查找存在时,将节点移动到链表头部并返回值
      • 不存在时返回-1
    • put操作
      • 已存在时更新值并移动到头部
      • 不存在时先检查容量,满时删除链表尾部元素
      • 插入新元素到链表头部并更新哈希表
  3. 边界处理

    • 构造函数处理非法容量值(负数自动设为0)
    • 容量为0时缓存不可用
    • 正确处理链表空时的删除操作
  4. 时间复杂度

    • get和put操作的时间复杂度均为O(1)
    • 链表操作使用splice实现节点移动,保证O(1)时间复杂度

在原有LRU缓存实现基础上,可以通过以下方案优化线程安全问题:

优化方案一:基础互斥锁版本

#include <list>
#include <unordered_map>
#include <mutex>class UpdateCaching {
private:int max_capacity;list<pair<int, int>> cache_list;unordered_map<int, list<pair<int, int>>::iterator> cache_map;mutable mutex cache_mutex; // 可变的互斥锁public:UpdateCaching(int capacity) : max_capacity(max(0, capacity)) {}int get(int key) {lock_guard<mutex> lock(cache_mutex); // 自动加锁if (auto it = cache_map.find(key); it != cache_map.end()) {cache_list.splice(cache_list.begin(), cache_list, it->second);return it->second->second;}return -1;}void put(int key, int value) {lock_guard<mutex> lock(cache_mutex);if (max_capacity <= 0) return;if (auto it = cache_map.find(key); it != cache_map.end()) {it->second->second = value;cache_list.splice(cache_list.begin(), cache_list, it->second);return;}if (cache_map.size() >= max_capacity) {cache_map.erase(cache_list.back().first);cache_list.pop_back();}cache_list.emplace_front(key, value);cache_map[key] = cache_list.begin();}
};

优化方案二:读写锁版本(C++17+)

#include <shared_mutex>class UpdateCaching {// ...其他成员同基础版...mutable shared_mutex rw_mutex; // 读写锁public:int get(int key) {shared_lock<shared_mutex> lock(rw_mutex); // 共享锁// ...原有逻辑...}void put(int key, int value) {unique_lock<shared_mutex> lock(rw_mutex); // 独占锁// ...原有逻辑...}
};

优化分析说明:

  1. 线程安全实现

    • 使用std::mutex保护所有缓存操作
    • 通过lock_guard自动管理锁的生命周期
    • 读写分离版本采用shared_mutex提升读多写少场景性能
  2. 性能影响评估

    方案读并发写并发适用场景
    普通互斥锁串行串行低并发通用场景
    读写锁并行读串行写读多写少的高并发场景
  3. 异常安全

    • 所有容器操作保证基本异常安全
    • 使用RAII风格的锁管理确保不会死锁
  4. 扩展优化建议

    // 示例:分段锁优化(适用于超高并发场景)
    class SegmentedLRUCache {constexpr static int SEGMENTS = 16;array<mutex, SEGMENTS> segment_mutexes;array<UpdateCaching, SEGMENTS> segments;size_t get_segment(int key) {return hash<int>{}(key) % SEGMENTS;}
    public:int get(int key) {auto seg = get_segment(key);lock_guard<mutex> lock(segment_mutexes[seg]);return segments[seg].get(key);}// 类似实现put方法...
    };
    

建议根据实际使用场景选择优化方案:

  • 常规服务:基础互斥锁方案即可满足需求
  • 高频读取服务:升级到读写锁版本
  • 超大规模并发:考虑分段锁或无锁队列方案

需要特别注意:线程安全实现会带来约10%-30%的性能损耗,在单线程场景中可以通过编译选项禁用锁机制(通过条件编译或模板策略)。

相关文章:

实现一个 LRU 风格的缓存类

实现一个缓存类 需求描述豆包解决思路&#xff1a;实现代码&#xff1a;优化11. std::list::remove 的时间复杂度问题2. 代码复用优化后的代码优化说明 优化21. 边界条件检查2. 异常处理3. 代码封装性4. 线程安全优化后的代码示例优化说明 DeepSeek&#xff08;深度思考R1&…...

【蓝桥杯嵌入式】4_key:单击+长按+双击

1、电路图 将4个按键的引脚设置为input&#xff0c;并将初始状态设置为Pull-up&#xff08;上拉输入&#xff09; 为解决按键抖动的问题&#xff0c;我们使用定时器中断进行消抖 打开TIM3时钟并设置参数&#xff0c;中断间隔10ms&#xff0c;当计数达到10000时溢出。80M/80/10…...

深入理解 C# 与.NET 框架

.NET学习资料 .NET学习资料 .NET学习资料 一、引言 在现代软件开发领域&#xff0c;C# 与.NET 框架是构建 Windows、Web、移动及云应用的强大工具。C# 作为一种面向对象的编程语言&#xff0c;而.NET 框架则是一个综合性的开发平台&#xff0c;它们紧密结合&#xff0c;为开…...

10. 神经网络(二.多层神经网络模型)

多层神经网络&#xff08;Multi-Layer Neural Network&#xff09;&#xff0c;也称为深度神经网络&#xff08;Deep Neural Network, DNN&#xff09;&#xff0c;是机器学习中一种重要的模型&#xff0c;能够通过多层次的非线性变换解决复杂的分类、回归和模式识别问题。以下…...

spark 性能调优 (一):执行计划

在 Spark 中&#xff0c;explain 函数用于提供数据框&#xff08;DataFrame&#xff09;或 SQL 查询的逻辑计划和物理执行计划的详细解释。它可以帮助开发者理解 Spark 是如何执行查询的&#xff0c;包括优化过程、转换步骤以及它将采用的物理执行策略。 1. 逻辑计划 (Logical…...

“卫星-无人机-地面”遥感数据快速使用及地物含量计算的实现方法

在与上千学员交流过程中&#xff0c;发现科研、生产和应用多源遥感数据时&#xff0c;能快速上手&#xff0c;发挥数据的时效性&#xff0c;尽快出创新性成果&#xff0c;是目前的学员最迫切的需求。特别是按照“遥感数据获取-处理-分析-计算-制图”全流程的答疑解惑&#xff0…...

杨氏数组中查找某一数值是否存在

判断数据是否存在于杨氏矩阵中 &#xff08;小米真题&#xff09; 题目&#xff1a;有一个数字矩阵&#xff0c;矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的&#xff0c;请编写程序在这样的矩阵中查找某个数字是否存在。 要求&#xff1a;时间复杂度小于O(N) …...

c语言对应汇编写法(以中微单片机举例)

芯片手册资料 1. 赋值语句 C语言&#xff1a; a 5; b a; 汇编&#xff1a; ; 立即数赋值 LDIA 05H ; ACC 5 LD R01,A ; R01 ACC&#xff08;a5&#xff09;; 寄存器间赋值 LD A,R01 ; ACC R01&#xff08;读取a的值&#xff09; LD R02,A ; R02 ACC&…...

详解CSS `clear` 属性及其各个选项

详解CSS clear 属性及其各个选项 1. clear: left;示例代码 2. clear: right;示例代码 3. clear: both;示例代码 4. clear: none;示例代码 总结 在CSS布局中&#xff0c;clear 属性是一个非常重要的工具&#xff0c;特别是在处理浮动元素时。本文将详细解释 clear 属性及其各个选…...

算法设计与分析三级项目--管道铺设系统

摘 要 该项目使用c算法逻辑&#xff0c;开发环境为VS2022&#xff0c;旨在通过Prim算法优化建筑物间的连接路径&#xff0c;以支持管线铺设规划。可以读取文本文件中的建筑物名称和距离的信息&#xff0c;并计算出建筑物之间的最短连接路径和总路径长度&#xff0c;同时以利用…...

Page Assist - 本地Deepseek模型 Web UI 的安装和使用

Page Assist Page Assist是一个开源的Chrome扩展程序&#xff0c;为本地AI模型提供一个直观的交互界面。通过它可以在任何网页上打开侧边栏或Web UI&#xff0c;与自己的AI模型进行对话&#xff0c;获取智能辅助。这种设计不仅方便了用户随时调用AI的能力&#xff0c;还保护了…...

VMware Win10下载安装教程(超详细)

《网络安全自学教程》 从MSDN下载系统镜像&#xff0c;使用 VMware Workstation 17 Pro 安装 Windows 10 consumer家庭版 和 VMware Tools。 Win10下载安装 1、下载镜像2、创建虚拟机3、安装操作系统4、配置系统5、安装VMware Tools 1、下载镜像 到MSDN https://msdn.itellyou…...

DS目前曲线代替的网站汇总

DS目前还不稳定&#xff0c;好在国内外大厂平台都上线了&#xff0c;汇总如下&#xff1a; 秘塔搜索&#xff1a; https://metaso.cn 360纳米AI搜索&#xff1a; https://www.n.cn/ 硅基流动&#xff1a; https://cloud.siliconflow.cn/i/snHnLED8 字节跳动火山引擎&#xf…...

具有HiLo注意力的快速视觉Transformer

摘要 https://arxiv.org/pdf/2205.13213 视觉Transformer(ViTs)在计算机视觉领域引发了最新且最重要的突破。其高效设计大多以计算复杂度的间接指标,即浮点运算数(FLOPs)为指导,然而,该指标与吞吐量等直接指标之间存在明显差距。因此,我们建议使用目标平台上的直接速度…...

《AI “造脸术”:生成对抗网络打造超真实虚拟人脸》

在科技飞速发展的当下&#xff0c;人工智能的浪潮席卷而来&#xff0c;其中生成对抗网络&#xff08;GANs&#xff09;技术以其独特的魅力&#xff0c;成为了生成高度真实感虚拟人脸的强大引擎。无论是影视制作中虚拟角色的塑造&#xff0c;还是游戏领域中多样化角色形象的构建…...

2025.2.6总结

今天想聊聊工作。 1.到底什么是工作&#xff1f; 个人理解&#xff0c;工作就是在规定的时间下&#xff0c;高质量的完成领导交代的任务。刚开始工作时&#xff0c;我只懂一味的埋头苦干&#xff0c;能干多少干多少&#xff0c;最后结果怎么样我也不是很在乎。后面&#xff0…...

RK3576——USB3.2 OTG无法识别到USB设备

问题&#xff1a;使用硬盘接入到OTG接口无热插拔信息&#xff0c;接入DP显示屏无法正常识别到显示设备&#xff0c;但是能通过RKDdevTool工具烧录系统。 问题分析&#xff1a;由于热插拔功能实现是靠HUSB311芯片完成的&#xff0c;因此需要先确保HUSB311芯片驱动正常工作。 1. …...

低代码系统-插件功能分析( 某道云)

本文主要把其的插件进行了简单分析&#xff0c;不做业务上的梳理&#xff0c;不做推荐。 可大致分为&#xff1a; 群机器人 信息查询 智能识别 实名验证类 数据库类 通知类 通知类 aPaas增强 考勤同步 财务类 类别 插件名称 功能简介 群机器人类 某钉机器人 即在表单处完…...

如何在 FastAPI 中使用本地资源自定义 Swagger UI

要自定义 FastAPI 中的 Swagger UI&#xff0c;且使用本地资源来代替 CDN。只是需要稍微修改一下。 修改后的代码&#xff1a; 步骤&#xff1a; 挂载本地静态文件目录&#xff1a;我们将本地的 Swagger UI 资源文件&#xff08;如 .js, .css, favicon.png 等&#xff09;放…...

wxWidgets生成HTML文件,带图片转base64数据

编译环境大家可以看我之前的文章,CodeBlocks + msys2 + wx3.2,win10 这里功能就是生成HTML文件,没用HTML库,因为是自己固定的格式,图片是一个vector,可以动态改变数量的。 效果如下: #include <wx/string.h> #include <wx/file.h> #include <wx/ima…...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

【技巧】dify前端源代码修改第一弹-增加tab页

回到目录 【技巧】dify前端源代码修改第一弹-增加tab页 尝试修改dify的前端源代码&#xff0c;在知识库增加一个tab页"HELLO WORLD"&#xff0c;完成后的效果如下 [gif01] 1. 前端代码进入调试模式 参考 【部署】win10的wsl环境下启动dify的web前端服务 启动调试…...

智警杯备赛--excel模块

数据透视与图表制作 创建步骤 创建 1.在Excel的插入或者数据标签页下找到数据透视表的按钮 2.将数据放进“请选择单元格区域“中&#xff0c;点击确定 这是最终结果&#xff0c;但是由于环境启不了&#xff0c;这里用的是自己的excel&#xff0c;真实的环境中的excel根据实训…...

Docker环境下安装 Elasticsearch + IK 分词器 + Pinyin插件 + Kibana(适配7.10.1)

做RAG自己打算使用esmilvus自己开发一个&#xff0c;安装时好像网上没有比较新的安装方法&#xff0c;然后找了个旧的方法对应试试&#xff1a; &#x1f680; 本文将手把手教你在 Docker 环境中部署 Elasticsearch 7.10.1 IK分词器 拼音插件 Kibana&#xff0c;适配中文搜索…...

解决MybatisPlus使用Druid1.2.11连接池查询PG数据库报Merge sql error的一种办法

目录 前言 一、问题重现 1、环境说明 2、重现步骤 3、错误信息 二、关于LATERAL 1、Lateral作用场景 2、在四至场景中使用 三、问题解决之道 1、源码追踪 2、关闭sql合并 3、改写处理SQL 四、总结 前言 在博客&#xff1a;【写在创作纪念日】基于SpringBoot和PostG…...

GC1808:高性能音频ADC的卓越之选

在音频处理领域&#xff0c;高质量的音频模数转换器&#xff08;ADC&#xff09;是实现精准音频数字化的关键。GC1808&#xff0c;一款96kHz、24bit立体声音频ADC&#xff0c;以其卓越的性能和高性价比脱颖而出&#xff0c;成为众多音频设备制造商的理想选择。 GC1808集成了64倍…...

ubuntu系统 | docker+dify+ollama+deepseek搭建本地应用

1、docker 介绍与安装 docker安装:1、Ubuntu系统安装docker_ubuntu docker run-CSDN博客 docker介绍及镜像源配置:2、ubuntu系统docker介绍及镜像源和仓库配置-CSDN博客 docker常用命令:3、ubuntu系统docker常用命令-CSDN博客 docker compose安装:4、docker compose-CS…...

时间序列预测的机器学习方法:从基础到实战

时间序列预测是机器学习中一个重要且实用的领域&#xff0c;广泛应用于金融、气象、销售预测、资源规划等多个行业。本文将全面介绍时间序列预测的基本概念、常用方法&#xff0c;并通过Python代码示例展示如何构建和评估时间序列预测模型。 1. 时间序列预测概述 时间序列是按…...

typeof运算符 +unll和undefined的区别

typeof运算符 JavaScript 有三种方法&#xff0c;可以确定一个值到底是什么类型。而我们 现在需要接触到的就是typeof 数值返回number 1 typeof 123 // "number" 字符串返回string 1 typeof 123 // "string" 布尔值返回boolean 1 typeof fal…...

Oracle 19c RAC集群ADG搭建

1、将主库的pfile和passwdfile发送到备库 #主库一节点操作 scp -P1234 /tmp/pfile2025.ora bak_ip:/home/oracle sco -P1234 /oracle/app/oracle/product/19.0.0/db/dbs/orapw$ORACLE_SID bak_ip:/oracle/app/oracle/product/19.0.0/db/dbs 2、备库修改参数文件成standby相关…...