Redis数据库笔记—— Hash(哈希)的扩容机制(rehash)
大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。详细介绍Hash(哈希)的扩容机制(rehash)、源码、以及扩容和缩容过程。
文章目录
- Redis 字典(dict)结构
- 源码
- 哈希表结构定义
- 渐进式哈希扩容(rehash)
- 渐进式哈希的优点
- 扩容机制:rehash
- 扩容条件
- 扩容过程
- 缩容机制:rehash
- 缩容条件
- 缩容过程
- 图示 rehash 操作
- 1. 开始 Rehash
- 2. Rehash 进行中
- 3. 节点迁移完毕
- 4. Rehash 完毕
- 字典的扩容和渐进式 rehash 实现
- Rehash 的影响与优化
- rehash执行的操作
- 查询操作
- 添加操作
- 总结
- 历史文章
- MySQL数据库
- Redis
Redis 的 Hash 类型是一个非常重要的数据结构,用于存储键值对的映射关系。它背后使用的是一种哈希表(hash table)结构,提供高效的 O(1) 时间复杂度进行插入、查找和删除操作。然而,当哈希表中的元素逐渐增多时,可能会触发哈希表的 扩容(rehash) 操作,以保证数据结构的高效性和性能。
Redis 字典(dict)结构
Redis 中的字典(dict
)是一个使用哈希表实现的高效数据结构,它包含以下基本元素:
- 键值对:每个元素是一个
key
和value
的配对,Redis 通过哈希表将key
映射到value
。 - 哈希表:采用链地址法的哈希表,桶(bucket)用于存储哈希值冲突的元素。
源码
哈希表结构定义
Redis 的字典(dict
)使用了哈希表(dictht
)作为其基本存储结构。每个字典(dict
)由两个哈希表组成,这两个哈希表用于实现 渐进式 rehash(渐进式扩容)。下面是哈希表相关的结构定义:
1. 单个节点:
- dictEntry:这是哈希表中的一个元素。每个元素包含一个键(
key
)和值(v
),并且每个节点指向下一个哈希表节点(形成链地址法)。
typedef struct dictEntry {void *key; // 键union {void *val; // 值(可以是任意类型)uint64_t u64; // 无符号64位整型值int64_t s64; // 有符号64位整型值} v;dictEntry *next; // 指向下一个哈希表节点(链表形式)
} dictEntry;
2. 哈希表:
- dictht:这是哈希表本身的结构,包含哈希表的大小、掩码、已使用的节点数以及哈希表数组(
table
),数组中的每个项是dictEntry
链表的头节点。
typedef struct dictht {dictEntry **table; // 哈希表数组,表的每个元素是一个链表的头节点unsigned long size; // 哈希表大小unsigned long sizemask; // 哈希表大小掩码,size - 1unsigned long used; // 哈希表当前已使用的节点数
} dictht;
3. 字典结构体:
- dict:字典结构体,包含两个
dictht
(旧表和新表),用于实现渐进式哈希扩容,还包含指向dictType
(类型特定函数)的指针和当前正在执行的安全迭代器的数量。
typedef struct dict {dictType *type; // 类型特定函数void *privdata; // 私有数据dictht ht[2]; // 两张哈希表:ht[0] 是旧表,ht[1] 是新表int rehashidx; // rehash 索引(标识当前扩容进度)int iterators; // 当前正在运行的迭代器数量
} dict;
渐进式哈希扩容(rehash)
在 Redis 中,哈希表的扩容(rehash)采用渐进式的方法。这意味着哈希表的扩容不是一次性完成的,而是通过多次操作逐步迁移数据,避免阻塞。具体扩容的过程是基于桶(bucket)为单位进行的,每次迁移一个桶的数据,直到完成迁移。
核心函数:dictRehash
该函数实现了渐进式的哈希扩容。它接受一个参数 n
,表示希望执行的步骤数,每次执行一步操作。以下是该函数的主要步骤和逻辑:
int dictRehash(dict *d, int n) {int empty_visits = n * 10; // 最多访问的空桶数if (!dictIsRehashing(d)) return 0; // 如果没有进行 rehash,直接返回while (n-- && d->ht[0].used != 0) { // 如果有数据需要迁移dictEntry *de, *nextde;assert(d->ht[0].size > (unsigned long)d->rehashidx); // 确保 rehashidx 没有越界while (d->ht[0].table[d->rehashidx] == NULL) { // 跳过空桶d->rehashidx++;if (--empty_visits == 0) return 1; // 如果访问空桶次数超过限制,返回1,继续执行下一次}de = d->ht[0].table[d->rehashidx]; // 当前桶// 将当前桶中的所有元素迁移到新哈希表while (de) {uint64_t h;nextde = de->next; // 记录下一个节点h = dictHashKey(d, de->key) & d->ht[1].sizemask; // 计算新哈希表的桶索引de->next = d->ht[1].table[h]; // 将元素插入新哈希表d->ht[1].table[h] = de;d->ht[0].used--; // 旧哈希表的元素减少d->ht[1].used++; // 新哈希表的元素增加de = nextde; // 继续处理下一个元素}d->ht[0].table[d->rehashidx] = NULL; // 清空旧表的已迁移桶d->rehashidx++; // 更新迁移的索引}// 检查是否已完成迁移if (d->ht[0].used == 0) {zfree(d->ht[0].table); // 回收旧哈希表空间d->ht[0] = d->ht[1]; // 旧表变为新表_dictReset(&d->ht[1]); // 重置新表d->rehashidx = -1; // 结束 rehashreturn 0; // 返回0,表示迁移完成}// 还有更多的元素需要迁移return 1;
}
函数逻辑分析:
-
判断是否正在进行 rehash:如果
rehashidx == -1
,则表示没有进行 rehash,因此直接返回0
。否则,进入扩容操作。 -
迁移数据:每次迁移一个桶的数据,直到迁移完当前
n
步的操作。每个桶可能包含多个哈希冲突的元素,因此会使用链地址法逐一迁移。 -
跳过空桶:在迁移过程中,
rehashidx
会跳过空桶。通过empty_visits
限制最多访问空桶的数量,防止迁移操作造成长时间阻塞。 -
迁移完成:当所有元素从旧哈希表迁移到新哈希表后,回收旧表的内存并重置新表。若迁移未完成,则返回
1
,表示还有数据需要迁移。
渐进式哈希的优点
-
性能优化:Redis 是单线程模型,如果在哈希表扩容时一次性迁移所有数据,可能会导致阻塞,影响性能。渐进式哈希通过逐步迁移数据,在后台处理扩容,避免了阻塞。
-
实时性:在大量数据迁移的过程中,Redis 仍然能够继续处理其他操作,不会因扩容而导致延迟或服务中断。
-
控制扩容步长:通过
dctRehash
函数中的n
参数,用户可以控制扩容的步长(桶的数量),避免扩容操作占用过多时间。
扩容机制:rehash
哈希表的负载因子是哈希表容量与存储的元素数量之间的比例。负载因子过大时,会导致哈希冲突增加,从而影响性能,因此需要进行扩容(rehash)操作。Redis 采用渐进式 rehash 机制,以平滑过渡的方式增加哈希表的容量,避免在 rehash 时导致性能的剧烈波动。
扩容条件
Redis 字典的扩容发生在以下条件下:
- 负载因子超过设定阈值时,触发扩容(rehash)。具体来说,当字典中的元素数量超过了字典容量的负载因子时,Redis 会自动扩容哈希表。
- 默认负载因子:Redis 默认的负载因子为 1,Redis 会将哈希表容量扩大为原来的 2 倍。
- 扩容是为了解决哈希冲突,提高哈希表的查找效率。
扩容过程
扩容是指当哈希表的负载因子过大时,Redis 会创建一个更大的哈希表,并将所有的元素重新映射到新的哈希表中。具体过程如下:
-
计算新大小:当哈希表的负载因子超过设定的阈值时,Redis 会将哈希表的容量扩大为原来大小的两倍。比如,如果当前字典大小为
N
,则新的字典大小会是2 * N
。 -
渐进式 rehash:为了避免在扩容时出现一次性大规模的性能抖动,Redis 采用了渐进式 rehash(Incremental Rehash)。在这种机制下,rehash 的过程并不是一次性完成的,而是分批进行的。具体来说,Redis 会在后续的操作中逐步完成哈希表从旧哈希表到新哈希表的元素迁移。
- 每次执行哈希表操作(如
SET
、GET
、DEL
等)时,Redis 会检查当前是否有需要迁移的元素。如果有迁移任务,它会将一部分元素(一个元素或者说是一个桶的元素)从旧表迁移到新表,并在之后的操作中继续迁移剩余的元素,直到迁移完毕。 - 这样可以避免一次性迁移所有元素导致的性能瓶颈,使得扩容过程对 Redis 的性能影响最小。
- 每次执行哈希表操作(如
-
完成 rehash 后:当所有元素迁移到新的哈希表后,Redis 将释放旧哈希表所占用的内存。
缩容机制:rehash
与扩容操作类似,当 Redis 中的哈希表负载因子过低时,Redis 会触发缩容(rehash) 操作,目的是为了节省内存并提高效率。缩容操作主要用于在键值对数量减少时,调整哈希表的大小,避免浪费内存。
缩容条件
Redis 字典的扩容发生在以下条件下:
- 当负载因子低于 0.1 时,Redis 会启动缩容操作。
- Redis 会将哈希表容量缩小为适应当前键值对数量的 2 的幂次方。
- 缩容的目的是节省内存空间,避免内存浪费。
如果现在哈希表中存储了 30 个键值对,2^5 = 32 (足够容纳 30 个键值对)。新的哈希表的大小会是 32。
缩容过程
缩容的过程与扩容类似,也是通过渐进式 rehash 来完成的,区别在于目标是减小哈希表的大小。
-
计算新大小:
- 当负载因子小于设定阈值时,Redis 会创建一个新的哈希表(
ht[1]
),其大小为当前哈希表的键值对数量所能容纳的最小 2 的幂次方。 - 如果
ht[0].used
(当前元素数量)为N
,则新的字典大小为不小于N
的 2 的幂次方。
- 当负载因子小于设定阈值时,Redis 会创建一个新的哈希表(
-
渐进式 rehash:
- 为了避免缩容时的性能瓶颈,Redis 会采用渐进式 rehash 机制,逐步将元素从旧的哈希表迁移到新的哈希表。
- 每当执行哈希表的操作时(如
SET
、GET
、DEL
等),Redis 会检查是否有待迁移的元素。如果有迁移任务,Redis 会将部分元素从旧哈希表(ht[0]
)迁移到新哈希表(ht[1]
)。 - 迁移操作会在每次操作中分批进行,直到所有元素都迁移完成,避免一次性迁移带来的性能压力。
-
完成 rehash 后:
- 当所有的元素迁移到新哈希表后,Redis 会释放旧哈希表所占用的内存。
- 此时,
ht[0]
被置为空表,ht[1]
成为新的哈希表。
图示 rehash 操作
来源
Redis 字典的 rehash 是一个用于扩展或收缩哈希表大小的过程。它涉及到重新分配空间,并逐步迁移键值对。以下是整个 rehash 过程的详细步骤,借助于例子,我们可以更清晰地理解 Redis 是如何管理字典的扩容和迁移的。
1. 开始 Rehash
在这一阶段,Redis 执行两个主要任务:
- 初始化
rehashidx
:rehashidx
被设置为0
,标识 rehash 过程的开始。 - 为
ht[1]
分配空间:新的哈希表ht[1]
会被分配至少是ht[0]
大小的两倍空间。
此时字典的状态如下:
- 旧哈希表 (
ht[0]
):存储原有键值对(例如 4 个键值对),并具有初步的哈希表大小(如大小 4)。 - 新哈希表 (
ht[1]
):开始创建,并分配空间(例如大小 8),但此时没有存储任何键值对。
2. Rehash 进行中
此时,rehashidx
的值被逐步增加,并表示 ht[0]
当前迁移到了哪个位置。逐步迁移的原因是 渐进式 rehash,即迁移过程不会一次性完成,而是分多次进行。
ht[0]
中的部分桶可能已经迁移,而ht[1]
中的部分桶已经开始填充新数据。- 以下是 rehashidx 值为 2 时,字典的样子:
3. 节点迁移完毕
当所有元素从 ht[0]
完全迁移到 ht[1]
后,ht[0]
变为空,且 ht[1]
中存储了所有键值对。此时,rehashidx
会被设置为 ht[1]
的最后一个桶位置,标志着迁移过程的完成。
4. Rehash 完毕
在 rehash 完成后,Redis 会:
- 释放
ht[0]
的空间:由于所有的键值对已经迁移到ht[1]
,ht[0]
中的空间可以被释放。 - 替换
ht[0]
和ht[1]
:ht[1]
被替换为新的ht[0]
,而ht[0]
的数据则会被丢弃(因为它已经变为空)。 - 更新字典的
rehashidx
:rehashidx
被设置为-1
,表示 rehash 完成,所有迁移工作已经结束。
此时,字典的哈希表已扩展,且容量已增加为 8
,可以容纳更多的键值对,且原有的键值对未发生任何变化。
字典的扩容和渐进式 rehash 实现
在 Redis 中,字典的扩容和渐进式 rehash 由以下几个函数实现:
dictExpand()
:用于扩容哈希表,当元素数量超过哈希表容量的阈值时,会调用该函数。dictResize()
:用于调整哈希表的大小,可以增加或减少容量。dictRehash()
:这是核心函数之一,用于将旧哈希表的元素迁移到新哈希表。迁移的过程是逐步进行的,不会阻塞客户端的请求。
Rehash 的影响与优化
- 性能优化:Redis 通过渐进式 rehash 技术避免了扩容时的性能瓶颈。渐进式 rehash 的引入使得 Redis 可以在高并发环境下继续处理客户端请求,极大地提升了扩容操作的效率。
- 内存优化:通过扩容和缩容,Redis 在保证性能的同时有效地使用内存。当负载因子较高时,扩容可以避免哈希冲突过多,保证查询性能;而当元素较少时,缩容可以释放内存。
- 内存浪费:尽管 Redis 尝试通过自动扩容和缩容来优化内存使用,但在一些极端情况下(比如字典大小变化较大时),可能会造成一定的内存浪费。
rehash执行的操作
查询操作
- 在进行哈希表查询(例如
GET
操作)时,Redis 会先检查 旧哈希表(ht[0]
)。 - 如果在 旧哈希表 中找到了匹配的元素,Redis 会返回该元素。
- 如果元素不在旧哈希表中,Redis 会继续查找 新哈希表(
ht[1]
),即使在进行 rehash 的过程中,新哈希表中的元素还在逐步迁移。
添加操作
在渐进式rehash执行期间,新添加到字典的键值对一律会被保存到ht[1]里面,而ht[0]则不再进行任何添加操作,这一措施保证了ht[0]包含的键值对数量会只减不增,并随着rehash操作的执行而最终变成空表。
总结
Redis 字典(dict
)的扩容机制是通过 渐进式 rehash 实现的,这使得在扩容时 Redis 可以保持高效的性能。每当字典达到一定负载因子时,Redis 会通过将哈希表的大小扩大一倍,并逐步将元素迁移到新表中,以保证系统稳定运行。同时,Redis 还支持缩容操作,以节省内存。渐进式 rehash 是 Redis 的一项关键优化,保证了 Redis 在高并发和大数据量情况下的高效性。
历史文章
MySQL数据库
- MySQL数据库笔记——数据库三范式
- MySQL数据库笔记——存储引擎(InnoDB、MyISAM、MEMORY、ARCHIVE)
- MySQL数据库笔记——常见的几种锁分类
- MySQL数据库笔记——索引介绍
- MySQL数据库笔记——事务介绍
- MySQL数据库笔记——索引结构之B+树
- MySQL数据库笔记——索引潜规则(回表查询、索引覆盖、索引下推)
- MySQL数据库笔记——索引潜规则(最左前缀原则)
- MySQL数据库笔记——常见慢查询优化方式
- MySQL数据库笔记——日志介绍
- MySQL数据库笔记——多版本并发控制MVCC
- MySQL数据库笔记——主从复制
Redis
- Redis数据库笔记——数据结构类型
- Redis数据库——Redis雪崩、穿透、击穿
- Redis数据库——内存淘汰机制
- Redis数据库笔记——内存分配器
- Redis数据库笔记——内存预分配
相关文章:
Redis数据库笔记—— Hash(哈希)的扩容机制(rehash)
大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。详细介绍Hash(哈希)的扩容机制(rehash)、源码、以及扩容和缩容过程。 文章目录 Redis 字典(dict)结构源码哈希…...
【Web】软件系统安全赛CachedVisitor——记一次二开工具的经历
明天开始考试周,百无聊赖开了一把CTF,还顺带体验了下二开工具,让无聊的Z3很开心🙂 CachedVisitor这题 大概描述一下:从main.lua加载一段visit.script中被##LUA_START##(.-)##LUA_END##包裹的lua代码 main.lua loca…...
面向对象分析与设计Python版 建模工具UML
文章目录 一、建模与模型二、统一建模语言 一、建模与模型 建模与模型 建模 modeling: 把不太理解的东西和一些已经较为理解、且十分类似的东西做比较,可以对这些不太理解的东西产生更深刻的理解,叫做建模重要的研发成果常常产自类比 模型 …...
Flink系列知识讲解之:深入了解 Flink 的网络协议栈
Flink系列知识之:深入了解 Flink 的网络协议栈 Flink 的网络协议栈是组成 flink-runtime 模块的核心组件之一,也是每个 Flink 任务的核心。它连接着来自所有任务管理器的各个工作单元(子任务)。这是流数据流过的地方,…...
动态库dll与静态库lib编程4:MFC规则DLL讲解
文章目录 前言一、说明二、具体实现2.1新建项目2.2 模块切换的演示 总结 前言 动态库dll与静态库lib编程4:MFC规则DLL讲解。 一、说明 1.前面介绍的均为Win32DLL,即不使用MFC的DLL。 2.MFC规则DLL的特点:DLL内部可以使用MFC类库、可以被其他…...
TypeScript 后端开发中的热重载编译处理
在一些除了nest框架外的一些其他nodejs框架中没有提供对ts编译和热重载,如果使用typescript我们需要自己进行配置。 方法一(推荐) 使用bun运行环境(快)。注:一些不是使用js,ts代码编写的第三方…...
ORB-SLAM3源码学习:LoopClosing.cc:LoopClosing::NewDetectCommonRegions检测共同区域
前言 在ORB-SLAM2中校验闭环候选关键帧时,需要满足时序上连续3次成功校验才能通过。这就需要检测至少3个新进来的关键帧,这种方法牺牲了召回率来提升精度。由于必须严格的满足至少连续的三个条件这使得闭环的条件更加严格,即使存在真实的闭环…...
前端React Router从入门到进阶实战
React Router 是 React 应用中的一个重要库,它用于实现客户端的路由管理,能够将 URL 路径与 React 组件关联起来,从而实现页面之间的导航。React Router 不会像传统的多页面应用那样重新加载页面,而是通过组件切换来呈现不同的视图…...
关于华硕Armoury Crate(奥创中心)安装程序失败、卡进度条问题解决方案
关于华硕Armoury Crate(奥创中心)安装失败解决方案 清理旧版本文件 如果之前安装过Armoury Crate,可能有残留文件导致冲突: 利用官方的卸载工具,卸载旧版本: https://www.asus.com.cn/supportonly/armoury%20crate/…...
【WPF】 数据绑定机制之INotifyPropertyChanged
INotifyPropertyChanged 是 WPF 中的一个接口,用于实现 数据绑定 中的 属性更改通知。它的主要作用是,当对象的某个属性值发生更改时,通知绑定到该属性的 UI 控件更新其显示内容。 以下是有关 INotifyPropertyChanged 的详细信息和实现方法&…...
QPushButton的基础用法
概述 本文将详细介绍 QPushButton 的概念、常规用法、样式表以及一些特殊用法,帮助您深入理解和高效应用 QPushButton。当前Qt版本为6.8。 1. QPushButton 的基本概念 1.1 概述 QPushButton 是 Qt 中最常用的按钮控件之一,它表示一个可以被点击的按钮…...
股指期货有哪些优势?
股指期货,作为一种重要的金融衍生品,以其独特的交易方式和多样的优势,吸引了众多投资者的关注。本文将详细解析股指期货的定义、优势以及特点,帮助投资者更好地理解和把握这一市场。 一、股指期货的定义 股指期货,顾…...
STM32完全学习——FATFS0.15移植SD卡
一、下载FATFS源码 大家都知道使用CubMAX可以很快的将,FATFS文件管理系统移植到单片机上,但是别的芯片没有这么好用的工具,就需要自己从官网下载源码进行移植。我们首先解决SD卡的驱动问题,然后再移植FATFS文件管理系统。 二、SD…...
使用 Spring 状态机构建灵活的状态管理系统
引言 在软件开发中,状态机是一种非常重要的工具,尤其适用于需要处理复杂状态转换的场景。无论是订单管理系统中的订单状态、工作流引擎中的任务流转,还是审批流程的管理,状态机都能有效地帮助我们组织和管理不同的状态及其之间的…...
[SMARTFORMS] 添加设置图标
本地图片存放位置 使用事务码SE78进入表格图形管理页面,将导入图标到SAP系统 选择需要上传的图片地址,输入名称,描述和图片类型,点击导入按钮 完成上述操作以后,图标已导入到SAP系统中 提示Tips:如何将图标…...
网络世界的“交通规则”——TCP/IP(一)
一、非可靠传输的协议——UDP 1.1 UDP的报文格式 (1)UDP长度:表示整个UDP数据包的长度(报头载荷); (2)校验和:用于验证UDP数据包在传输过程中有没发生比特翻转ÿ…...
Excel中公式和函数的区别
Excel中公式和函数的区别 概念讲解例子公式函数 详细介绍函数面板最后再次进行演示操作文档 概念讲解 公式是用户自己编写的表达式,而函数是由Excel预定义的操作。公式可以包含各种数学运算符和逻辑表达式,函数则是执行特定任务的工具。公式可以引用其他…...
Node.js应用程序遇到了内存溢出的问题
vue 项目 跑起来,一直报错,内存溢出 在 文件node_modules 里 .bin > vue-cli-service.cmd 在依赖包这个文件第一行加上这个 node --max-old-space-size102400 "%~dp0\..\vue\cli-service\bin\vue-cli-service.js" %* node --max-old-s…...
MySQL关联关系理论与实践
MySQL 是一种关系型数据库管理系统,以其高性能、灵活性和易用性在开发者中广受欢迎。在 MySQL 中,数据存储以表格形式存在,表与表之间的关联关系构成了关系型数据库的核心。本篇文章将介绍 MySQL 关联关系的理论基础和常见实践,包…...
w138基于Spring Boot的宠物领养系统的设计与实现
🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...
AMBA-CHI协议详解(十三)
AMBA-CHI协议详解(一)- Introduction AMBA-CHI协议详解(二)- Channel fields / Read transactions AMBA-CHI协议详解(三)- Write transactions AMBA-CHI协议详解(四)- Other transac…...
组合的能力
在《德鲁克最后的忠告》一书中,有这样一段话: 企业将由各种积木组建而成:人员、产品、理念和建筑。积木的设计组合至少和其供给一样重要。……对于一切程序、应用软件以及附件来说,重要的是掌握将已有的软件模块组合的能力&…...
若依使用 Undertow 替代 Tomcat 容器
文章目录 需求提出应用场景解决思路注意事项完整代码第一步:在 ruoyi-framework/pom.xml 文件中进行依赖配置第二步:修改 application.yml 配置文件第三步:修改文件上传工具类 FileUploadUtils.java 运行结果 需求提出 在开发若依框架的前后…...
STC单片机 IAP在线升级功能的使用介绍
STC单片机 IAP在线升级功能的使用介绍 从官方给出的IAP在线升级的demo示例来看,目前支持的型号有STC8、STC12、STC15、STC32,前提是需要使用64K/128K容量的型号。只支持用户程序容量小于60K 的项目。 🌿IAP在线升级方式支持:CAN、…...
visio 0xC004F017
1.好久没用的电脑突然显示Office tool plus 的软件(visio)失效了 显示错误代码: 0xC004F017 2.在软件中重新配置 关键:KMS用了 kms.03k.org 3.在软件中重新配置 许可选择 4.一些额外的检查方法 打开控制台输入 slmgr /dlv 中间过程 还遇到过【错误…...
IoC设计模式详解:控制反转的核心思想
前言:在软件开发中,设计模式是一种经过验证的、在特定场景下能有效解决问题的解决方案。控制反转(Inversion of Control,IoC) 作为一种设计模式,通过让程序的控制流和对象管理反转,从而使得代码…...
C语言延时实现
C语言延时实现 在C语言中,delay 函数通过空循环实现延时,而不是像其他高级语言(如Python)直接使用 sleep 函数。这种实现方式是基于单片机的特性和C语言的底层操作。下面详细解释为什么这种空循环可以实现延时,以及它…...
CDP集群安全指南-静态数据加密
[一]静态数据加密的架构 CDP 支持两种加密组件,这些组件可以组合成独特的解决方案。在选择密钥管理系统(KMS)时,您需要决定哪些组件能够满足企业的密钥管理和加密需求。 CDP 加密组件 以下是 Cloudera 用于静态数据加密的组件描…...
# LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game)
LeetCode Problem 2038: 如果相邻两个颜色均相同则删除当前颜色 (Winner of the Game) 在本篇博客中,我们将深入探讨 LeetCode 第2038题——如果相邻两个颜色均相同则删除当前颜色。该问题涉及字符串处理与游戏策略,旨在考察如何在给定规则下判断游戏的…...
极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现
极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现 目录 极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现1. 极限学习机 (ELM) 算法概述1.1 单隐层前馈神经网络1.2 ELM的优势2. ELM的核心技术2.1 模型定义2.2 随机初始化2.3 最小二乘法2.4…...
【insert 插入数据语法合集】.NET开源ORM框架 SqlSugar 系列
系列文章目录 🎀🎀🎀 .NET开源 ORM 框架 SqlSugar 系列 🎀🎀🎀 文章目录 系列文章目录一、前言 🍃二、插入方式 💯2.1 单条插入实体2.2 批量 插入实体2.3 根据字典插入2.4 根据 Dat…...
什么是.net framework,什么是.net core,什么是.net5~8,版本对应关系
我不知道有多少人和我一样,没学习过.netCore,想要学习,但是版本号太多就蒙了,不知道学什么了,这里解释下各个版本的关系 我们一般开始学习微软的时候,都是开始学习的.netframework,常用的就是4…...
【数据库系统概论】数据库安全性和存取控制和视图机制以及审计、数据加密--复习极简总结版
1. 数据库安全性概述 1.1 数据库安全性的重要性 数据库安全性是保护数据库防止非法访问、数据泄露、篡改或破坏的能力。它随着数据共享和网络化应用的普及而变得至关重要。现实案例: 2016年,某国医院遭受黑客攻击,黑客加密数据库并勒索赎金…...
深入理解计算机系统—虚拟内存(3)
9.9 动态内存分配 虽然可以使用低级的 mmap 和 munmap 函数来创建和删除虚拟内存的区域,但是 C程序员还是会觉得当运行时需要额外虚拟内存时,用 动态内存分配器 更方便,也有更好的可移植性。 动态内存分配器维护着一个进程的虚拟内存区域&…...
Vue项目整合与优化
前几篇文章,我们讲述了 Vue 项目构建的整体流程,从无到有的实现了单页和多页应用的功能配置,但在实现的过程中不乏一些可以整合的功能点及可行性的优化方案,就像大楼造完需要进行最后的项目验收改进一样,有待我们进一步…...
MyBatis 与 MyBatis-Plus 的区别
MyBatis 和 MyBatis-Plus 都是用于简化 Java 应用程序与数据库交互的持久层框架,但它们在功能、易用性和性能优化方面存在显著差异。下面将详细介绍两者之间的区别,并通过具体的代码示例进行对比。 概述 MyBatis:作为一款经典的持久层框架&a…...
如何让大模型不再“已读乱回”——RAG技术助力生成更精确的答案
随着大语言模型(LLM) 的迅猛发展,越来越多的领域开始受益于其强大的自然语言处理能力。从写作到编程,LLM已成为我们日常生活和工作的得力助手。然而,这些看似无所不能的大模型,却有一个致命的弱点ÿ…...
Anaconda环境配置(Windows11+python3.9)
文章目录 一、 下载ANACONDA(1)点击**Free Download**。(2)点击“skip registration”,跳过登录。(3)下载对应操作系统的ANACONDA版本。 二、 安装ANACONDA(1)双击运行安…...
Spring Boot 中的虚拟线程
什么是虚拟线程? 虚拟线程(Virtual Threads)是 Java 19 引入的一项新特性,它属于 Project Loom 项目的一部分。与传统的线程(平台线程)不同,虚拟线程并不是由操作系统直接管理,而是…...
el-table 实现纵向多级表头
为了实现上图效果,最开始打算用el-row、el-col去实现,但发现把表头和数据分成两大列时,数据太多时会导致所在格高度变高。但由于每一格数据肯定不一样,为保持高度样式一致,就需要我们手动去获取最高格的高度之后再设置…...
探秘Kafka源码:关键内容解析
文章目录 一、以kafka-3.0.0为例1.1安装 gradle 二、生产者源码2.1源码主流程图2.2 初始化2.3生产者sender线程初始化2.4 程序入口2.5生产者 main 线程初始化2.6 跳转到 KafkaProducer构造方法 一、以kafka-3.0.0为例 打开 IDEA,点击 File->Open…->源码包解…...
Promise编码小挑战
题目 我们将实现一个 createImage 函数,该函数返回一个 Promise,用于处理图片加载的异步操作。此外,还会实现暂停执行的 wait 函数。 Part 1: createImage 函数 该函数会: 创建一个新的图片元素。将图片的 src 设置为提供的路径…...
PyQt实战——将pcm文本数据转换成.pcm的二进制文件
系类往期文章: PyQt5实战——多脚本集合包,前言与环境配置(一) PyQt5实战——多脚本集合包,UI以及工程布局(二) PyQt5实战——多脚本集合包,程序入口QMainWindow(三&…...
数据结构之线性表
1.什么是线性表 线性表的概念 定义:线性表是由n个数据元素组成的有限序列。每个数据元素(除了第一个和最后一个)都有且仅有一个前驱和一个后继。逻辑结构:线性表的逻辑结构可以用一个序列来表示,例如 L(a1,a2,…,an)。…...
量子行走的干涉性和叠加性
需要注意公式的一些特殊情况,举例,当dj2和dj3 dj2 dj3...
Fabric环境部署-安装Go
安装go语言环境 国内镜像:Go下载 - Go语言中文网 - Golang中文社区 1.选择版本下载后解压:注意go1.11.linux-amd64.tar.gz换成你下的 sudo tar zxvf go1.21.linux-amd64.tar.gz -C /usr/local 2.. 创建Go目录 mkdir $HOME/go 3. 用vi打开~./bashrc&…...
网站设计总结后期维护与更新的重要性
当我们谈论网站设计时,往往会聚焦在初始阶段的创意和实现上。然而,一旦网站建成并上线,后期维护与更新的重要性就显得尤为突出。一个网站的成功不仅取决于其初始设计,更在于持续的维护与更新。 首先,后期维护能够确保网…...
『SQLite』详解运算符
内容摘要:本节讲解运算符,包括:算术运算符、比较运算符、逻辑运算符和位运算符。 什么是运算符? 运算符是一个保留字或字符,主要用于 SQLite 语句的 WHERE 子句中执行操作。它用于指定 SQLite 语句中的条件࿰…...
计算机网络--根据IP地址和路由表计算下一跳
一、必备知识 1.无分类地址IPV4地址网络前缀主机号 2.每个IPV4地址由32位二进制数组成 3. /15这个地址表示网络前缀有15位,那么主机号32-1517位。 4.地址掩码(子网掩码):所对应的网络前缀为1,主机号为0。 5.计算下…...
如何使用 Ansys OptiSlang 同时运行多个参数化设计研究
了解如何通过使用 OptiSLang 同时运行多个参数化设计研究来提高工作效率。 了解参数化设计研究的重要性 参数化设计研究在工程和设计过程中起着至关重要的作用。通过改变输入参数,工程师可以探索不同设计选择的效果,并优化其设计以满足性能、成本或其他…...