Redis从入门到精通【高阶篇】之底层数据结构字典(Dictionary)详解

news2024/11/25 20:46:55

文章目录

  • 0.前言
  • 1. 字典的结构
  • 2. 源码解析
    • 2.1. 字典的结构体
    • 2.2. 字典的函数接口
      • dictAdd
      • dictFind
      • dictResize
  • 3. 字典/哈希表的优缺点
    • 3.1 优点
    • 3.1.1. 快速的查找时间
    • 3.1.2. 动态调整大小
    • 3.1.3. 灵活的数据类型
    • 3.2 缺点
  • 4.总结
  • 5. Redis从入门到精通系列文章

在这里插入图片描述

0.前言

上个篇章回顾,我们上个章节,讲了Redis中的快表(QuickList),它是一种特殊的数据结构,用于存储一系列的连续节点,每个节点可以是一个整数或一个字节数组。快表是Redis中的底层数据结构之一,常用于存储有序集合(Sorted Set)等数据类型的底层实现。

那么本章讲解Redis中的底层数据结构中的字典(Dictionary)也称为哈希表(Hash Table)。字典(Dictionary)是一种高效的数据结构,用于存储键值对,常用于实现哈希表。用于快速存取和查找数据的数据结构,它的内部实现是一个数组加上链表或者红黑树。在 Redis 中,字典被广泛用于实现哈希表键值对的存储和查找,例如 Redis 中的 Hash 类型就是基于字典实现的在本文中,我们将深入了解Redis中的字典/哈希表,包括字典的结构和操作等。

Redis中的字典(Dictionary)是一种高效的数据结构,用于存储键值对,常用于实现哈希表(Hash Table)。在本文中,我们将深入了解Redis中的字典/哈希表,包括字典的结构和操作等。
image.png
图1 哈希表(Hash Table)

1. 字典的结构

在这里插入图片描述

示意图中,RedisDictionary 表示 Redis 字典,它包含了多个 HashSlot 对象,每个 HashSlot
对象代表一个哈希槽,它包含了多个 Entry 对象,每个 Entry 对象代表一个键值对。

Redis中的字典(Dictionary)是由多个哈希表(Hash Table 如图1)组成的,每个哈希表都包含了多个哈希槽(Hash Bucket)。哈希表的结构如下图所示:

+---------+---------+---------+-------+
|  bucket |  bucket |  bucket |  ...  |
+---------+---------+---------+-------+
|  ...    |  ...    |  ...    |  ...  |
+---------+---------+---------+-------+

其中,bucket是哈希桶,包含了多个键值对。每个键值对包含了一个键和一个值,键和值可以是任意数据类型,但键必须是唯一的。哈希表的大小是固定的,当哈希桶中的键值对数量超过一定阈值时,需要对哈希表进行扩容操作,以保持哈希表的高效性。
Redis 6 字典的源码实现主要在 dict.h 和 dict.c 文件中。dict.h 文件定义了字典的结构体和函数接口,而 dict.c 文件则具体实现了这些函数接口。

2. 源码解析

2.1. 字典的结构体

Redis 6 字典的结构体定义与 Redis 5 相同,但是新增了一个 dictEntryKey 结构体,用于存储键的信息。Redis 6 字典的结构体定义如下:

typedef struct dictEntryKey {
    void *key;  // 指向键的指针
    uint64_t hash;  // 哈希值
} dictEntryKey;

typedef struct dictEntry {
    dictEntryKey key;  // 键的信息
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;

typedef struct dictType {
    uint64_t (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;
  1. dictEntryKey 结构体

    ``dictEntryKey 结构体用于存储键的信息,包括指向键的指针和键的哈希值。其中,key 成员变量是指向键的指针,hash` 成员变量是键的哈希值。

  2. dictEntry 结构体

    ``dictEntry 结构体用于表示字典中的一个节点,包含键值对的信息和指向下一个节点的指针。其中,key成员变量是dictEntryKey 结构体类型,表示键的信息;v成员变量是一个union,可以存储不同类型的值,包括指向值的指针、64 位整数、64 位有符号整数和双精度浮点数等;next` 成员变量是指向下一个节点的指针。

  3. dictType 结构体

    ``dictType` 结构体用于定义字典的类型,包括哈希函数、键复制函数、值复制函数、键比较函数、键销毁函数和值销毁函数。

    • hashFunction 成员变量是哈希函数,用于计算键的哈希值;
    • keyDup 成员变量是键复制函数,用于复制键的值;
    • valDup 成员变量是值复制函数,用于复制值的值;
    • keyCompare 成员变量是键比较函数,用于比较两个键是否相等;
    • keyDestructor 成员变量是键销毁函数,用于销毁键的值;
    • valDestructor 成员变量是值销毁函数,用于销毁值的值。
  4. dictht 结构体

    ``dictht 结构体用于表示哈希表,包括哈希表的数组、大小、掩码和已使用的节点数。其中,table 成员变量是指向哈希表数组的指针,size 成员变量是哈希表数组的大小,sizemask成员变量是掩码(等于size - 1),用于计算哈希值对应的数组下标,used` 成员变量是哈希表已使用的节点数。

  5. dict 结构体

    ``dict 结构体用于表示字典,包括字典的类型、私有数据、哈希表、重哈希索引和正在运行的迭代器数量。其中,type 成员变量是指向字典类型的指针,privdata 成员变量是指向私有数据的指针,ht成员变量是一个长度为 2 的dictht 数组,用于实现哈希表的渐进式重哈希操作;rehashidx成员变量表示正在进行重哈希的哈希表索引,如果rehashidx 等于 -1,表示没有进行重哈希操作;iterators` 成员变量表示正在运行的迭代器数量,用于控制在迭代器运行期间进行重哈希操作。

2.2. 字典的函数接口

Redis 6 字典提供了与 Redis 5 相同的函数接口,但是在实现细节上有一些变化。

dictAdd

Redis 6 相对于 Redis 5 做了一些优化,其中 dictAdd 函数的实现发生了变化。在 Redis 6 中,当向字典中添加一个新的键值对时,会先尝试将该键的哈希值计算出来,并查找哈希表中是否已经存在该哈希值。如果该哈希值还没有节点使用,那么就可以直接将新的键值对插入到哈希表中。如果该哈希值已经存在节点,那么就需要使用键比较函数来比较新键和旧键是否相等。如果新键和旧键相等,那么就需要用新值替换旧值;否则就需要将新键值对插入到哈希槽的链表末尾。

在实现过程中,Redis 6 使用了一个 dictEntryKey 结构体来存储键的信息,包括指向键的指针和键的哈希值。这样可以避免重复计算键的哈希值,提高了添加操作的效率。

dictFind

在 Redis 6 中,dictFind 函数的实现与 Redis 5 相同,但是在查找过程中,Redis 6 使用了 dictEntryKey 结构体中的哈希值来进行比较,以提高查找效率。

dictResize

Redis 6 中的 dictResize 函数与 Redis 5 相同,但是在实现过程中,Redis 6 增加了一些控制逻辑,以避免在短时间内多次调整哈希表的大小,从而提高了性能。

Redis 6 字典相对于 Redis 5 在实现细节上进行了一些优化,主要是在添加和查找操作上进行了改进,提高了字典的性能和效率。其中,添加操作使用了一个 dictEntryKey 结构体来存储键的信息,以避免重复计算键的哈希值;查找操作使用了dictEntryKey 结构体中的哈希值来进行比较,以提高查找效率。此外,Redis 6 还增加了一些控制逻辑,以避免在短时间内多次调整哈希表的大小,从而提高了性能。

如果有想继续链接Redis6源码的同学,可以参考github地址 https://github.com/redis/redis/tree/6.0,可以从这个 Github 仓库中获取整个 Redis 6 的代码。在该仓库中,可以找到所有与 Redis 相关的代码,包括服务器端、客户端、测试代码等等。如果需要了解 Redis 6 的源码实现,可以通过该仓库中的代码来深入了解 Redis 6 的实现细节。同时,Redis 官方也提供了详细的文档和说明,可以帮助开发者更好地理解 Redis 6 的设计思路和代码实现。

3. 字典/哈希表的优缺点

3.1 优点

3.1.1. 快速的查找时间

提供了常数时间复杂度O(1)的键值对查找,这意味着查找与字典大小无关,即使对于非常大的字典,查找时间也非常快。

3.1.2. 动态调整大小

字典/哈希表支持动态调整大小以适应数据的增长或减少。当某个哈希桶中的键值对数量超过一定阈值时,Redis会自动调整哈希桶的大小,以确保字典的高效性。这意味着Redis可以处理大量的数据而不会导致显著的性能损失。

3.1.3. 灵活的数据类型

可以存储任意数据类型的键和值,这使它非常灵活。这意味着它可以用于各种应用场景,从简单的键值存储到更复杂的数据结构。

3.2 缺点

  • 哈希表的空间利用率可能较低,当哈希桶中的键值对数量较少时,会浪费一定的空间。
  • 哈希表的扩容和缩容可能会造成性能损失,因为需要重新计算哈希值、重新分配内存等操作。
  • 哈希表中的键的顺序是无序的,不适合存储需要按照键的顺序进行访问的数据。

4.总结

字典/哈希表适合存储大量的键值对,并需要快速地查找键对应的值的场景。在实际应用中,需要根据具体的业务场景选择合适的底层数据结构。例如,如果需要按照键的顺序进行访问,可以使用有序集合(Sorted Set)等其他数据结构。

5. Redis从入门到精通系列文章

《Redis从入门到精通【高阶篇】之底层数据结构快表QuickList详解》
《Redis从入门到精通【高阶篇】之底层数据结构简单动态字符串(SDS)详解》
《Redis从入门到精通【高阶篇】之底层数据结构压缩列表(ZipList)详解》
《Redis从入门到精通【进阶篇】之数据类型Stream详解和使用示例》
在这里插入图片描述

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

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

相关文章

java三大特性之【多态】

多态 1.1 概念1.2 实现条件1.3 方法重写(override)与方法重载(overload)1.4 向上转型1.5 向下转型 1.1 概念 同样的一个方法/行为,经过不同的对象,表现出不同的行为,这样的现象就称为多态。 举…

今天就详细告诉你发票识别软件能识别哪些内容

既然大家点进这篇文章,说明大家对增值税发票识别技术非常感兴趣。本文会先介绍增值税发票识别技术的相关知识,然后再具体介绍识别增值税发票的软件有哪些。 增值税发票识别技术是一种基于图像识别和深度学习算法的自动化技术,它可以快速准确…

AI问答:前端需要掌握的设计模式/vue项目使用了哪些设计模式/vue项目开发可以使用哪些设计模式

一、理解什么是设计模式 设计模式是对软件设计开发过程中反复出现的某类问题的通用解决方案。 设计模式是一个在软件设计领域中被广泛应用的概念,它指的是一套被公认为有效的解决特定问题的设计思路和方法。 设计模式更多的是指导思想和方法论,而不是现…

零基础学 MySQL(基础版)

零基础学 MySQL(基础版) 1. 引出 思考一个问题: 淘宝网,京东、微信,抖音 都有各自的功能,那么当我们退出系统的时候,下次再访问时,为什么信息还存在? 2. 解决之道 2.1 解决之道—文件、数据库 为了解决上述问题&…

chatgpt赋能python:Introduction

Introduction 在机器学习中,模型的训练是非常重要的步骤之一。模型训练意味着为数据拟合合适的参数,以便能够准确地预测未来的值。Python是一种功能强大的编程语言,提供许多库和框架来训练机器学习模型。在本文中,我们将探讨如何…

FFmpeg编程入门

标题 播放器框架常用音视频术语解复用器和编解码器FFmpeg库简介FFmpeg有8个常用库: FFmpeg函数简介封装格式相关编解码器相关 FFmpeg数据结构简介关系数据结构分析 播放器框架 流程:媒体文件通过复用器将音频流,视频流,字幕流分离…

iCache dCache

前言 CPU 和 RAM 之间存在多级高速缓存,一般分为 3 级,分别是 L1、L2、L3。 另外,我们的代码都是由两部分组成的:指令、数据。 L1 Cache 比较特殊,每个 CPU 会有两个 L1 Cache,分别为 iCache(指…

互联网 Java 工程师高级面试八股文汇总(1260 道题目附解析)

今年的行情,让招聘面试变得雪上加霜。已经有不少大厂,如腾讯、字节跳动的招聘名额明显减少,面试门槛却一再拔高,如果不用心准备,很可能就被面试官怼得哑口无言,甚至失去了难得的机会。 现如今,…

苹果将在 iOS 17 引入新功能,Safari隐私浏览有重大更新

苹果公司正在对Safari隐私浏览系统进行重大更新,为用户在浏览网页时提供更好的保护,防止第三方跟踪器。 iPhone制造商说:先进的跟踪和指纹保护有助于防止网站使用最新的技术来跟踪或识别用户的设备。隐私浏览现在可以在不使用时锁定&#xf…

MODIS数据下载

MODIS数据常用下载网址: Find Data - LAADS DAAC 在下载之前需要注册一个账号,才可进行下载。 1.选择数据产品,本人选取MOD09Q1数据产品(250m8天合成的反射率数据) 2.设置时间限制如下 3.找到感研究区域所在的位置&…

chatgpt赋能python:Python怎么拦截Windows浏览器的请求

Python怎么拦截Windows浏览器的请求 Python是一种流行的编程语言,并且被广泛用于Web开发。在这篇文章中,我们将深入探讨Python如何拦截Windows浏览器的请求。 什么是拦截请求? 拦截请求是指在网络传输过程中,对请求进行截获并进行处理的过…

C++结构体

目录 一、结构体的概念 二、结构体定义和使用 三、结构体数组 四、结构体指针 五、结构体嵌套结构体 六、结构体做函数参数 七、结构体中const使用场景 一、结构体的概念 结构体属于用户自定义的数据类型,允许用户存储不同的数据类型 二、结构体定义和使用 语法&…

对称二叉树(C++)

题目描述 一棵有点权的有根树如果满足以下条件,则被轩轩称为对称二叉树: 1. 二叉树; 2. 将这棵树所有节点的左右子树交换,新树和原树对应位置的结构相同且点权相等。 下图中节点内的数字为权值,节点外的 id 表示节点编号。 现在给出一棵二叉…

Spring 事务的相关配置、传播行为、隔离级别及注解配置声明式事务

目录 一、事务的相关配置 1. 添加测试标签 2. 添加对应方法 3. 测试 二、事务的传播行为 三、事务的隔离级别 四、注解配置声明式事务 1. 注册事务注解驱动 2. 加上注解 3. 配置类代替xml文件中的注解事务支持 4. 测试 往期专栏&文章相关导读 1. Maven系列专栏…

用了【WRITE-BUG数字空间】,其他文档软件可以卸载、注销账号了

都3202年了文档都进化成在线协同编辑文档了 让我看看谁还在用本地软件写文档啊~滋滋滋 使用【WRITE-BUG数字空间】云文档全键盘写作不是梦!铁汁,听我句劝,把本地软件卸载了奥,你把握不住~ 程序员兄弟姐妹们的最爱编辑器&#x…

Zotero jasminum茉莉花插件

github地址:https://github.com/l0o0/jasminum 一个简单的Zotero 插件,用于识别中文元数据 非常感谢作者开发了这么好用的工具 安装步骤 首先要安装zotero 下载茉莉花插件安装包 https://github.com/l0o0/jasminum/releases 下载这个xpi格式的文件…

chatgpt赋能python:Python怎么抢优惠券?优惠不再是梦想!

Python怎么抢优惠券?优惠不再是梦想! 在如今的消费社会,优惠券已成为人们购物时追逐的目标。而优惠券的数量有限且抢手,往往仅能在短时间内领取,因此初次抢到心仪的优惠券可谓令人欣喜不已。而对于程序员们而言&#…

《springboot使用篇》——只为使用,一篇就够

目录 环境: spring boot概述 一,springboot快速入门 1.创建maven项目 2.引入起步依赖 3.自定义controller 4.编写启动类 5.开始测试 二.快捷方式创建sprinboot工程 补充 三,配置文件 1.配置文件之间的关系 2.yml配置文件 1.基本…

【ROS】ROS+Gazebo强化学习:训练

1、安装ROS1 【ROS】Ubuntu20.04安装ROS1 2、安装Anaconda 【AI】PyTorch入门(一):通过Anaconda安装PyTorch 【PyThon】Anaconda常用命令 3、源码下载 使用论文 Goal-Driven Autonomous Exploration Through Deep Reinforcement Learnin…

VMware虚拟机安装win10系统教程

执行本教程前请依次阅读以下2篇文章,完成环境准备: 1.VMware虚拟机下载安装教程【详细步骤 - 图文结合】 VMware虚拟机下载安装教程【详细步骤 - 图文结合】_西晋的no1的博客-CSDN博客 2.如何在微软官网下载win10镜像文件 如何在微软官网下载win10镜像文…