Redis_字典

阅读本文之前要了解的两件事情,第一,Redis是一种Key-Value数据库,第二,字典是一种保存键值对的抽象数据结构。所以不难猜出字典在Redis中应用一定非常广泛,实际上,Redis数据库的底层实现就是字典,对数据库的增删查改也是构建在对字典的操作上,那么想要深入理解Redis,字典的解密是必不可少的,接下来,就让我们一层一层解开指点的面纱,看看它的真面目。

首先看看Redis中有哪些地方使用到了字典

一, 数据库键空间

Redis是一个键值对数据库服务器,服务器中的每个数据库都是一个RedisDB结构,其中RedisDb结构的dict字典保存了数据库中的所有键值对,我们将这个字典称为键空间(key space),键空间和用户直接所见的数据库是直接对应的

二, Expires字典

Redis数据库结构是一个RedisDb结构,有一个属性expires也是字典,这个字典中保存了数据库中所有键的过期时间,我们称这个字典叫做过期字典

下面贴出RedisDb的数据结构,加深了理解。

三, 字典是Hash类型的底层实现之一

这里之所以说是之一,是应为Hash类型的实现可以是多种类型,在不同的场景下可以是不同的类型,但一个哈希键中包含的键值对比较多,有或者是键值对中元素都是比较长的字符串的时候,就会使用字典作为底层实现,否则就是压缩列表作为底层实现。

【注意】键空间中的键和过期字典中的键都指向都一个键对象,所以不会出现任何重复对象,也不会浪费内存空间。

然后我们来了解一下在Redis中字典是如何实现的。

字典的定义在dict.h/dict中给出了,如下:

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

这是一个哈希表,table数组中的每个元素都是指向一个dictEntry结构的指针,size是哈希表的大小,也就是table数组的大小,sizemask属性总是等于size-1 ,sizemask和哈希值一起决定将一个键应该被放到那个数组上,used表示目前哈希表有多少个节点,used/size 是一个哈希表的负载因子,这个因子决定了什么时候后对哈希表进行扩展和收缩。

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

下面是一个哈希表节点,每个dictEntry结构都保持着一个键值对,其中next指针可以将多个哈希值相同的键值对连接在一起,一次来解决键冲突的问题(这里可以引申出哈希函数以及哈希冲突解决方案,Redis中使用的解决方案是链地址法,就是,如果多个值通过哈希函数得到的哈希值是相同的,那么就链接到这个地址后,还有一种解决哈希冲突的方案,就是寻地址法,就是当出现哈希冲突的时候,对键值对在进行一个哈希函数,得到一个没有被占用的地址为止,这两种方案各有利弊,链地址法可能会退化成一个链表,寻地址法可能在后期插入时,全是冲突)

typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;

还有一个需要说的地方,就是哈希表的rehash

随着操作的不断执行,一个哈希表中保存的键值对会越来越多或者是越来越少,哈希表中键值对数量过多或者过少都是不好的,过多,就会相当于是多个链表,过少也不好,查找的命中率也会很低,将哈希表的负载因子(used/size)维持在一个范围之类是最好的,所以,当哈希表的数量过大或者过小的时候,程序会对哈希表进行扩展或者收缩,

扩展好理解,如果size=4 ,但是used=8,相当于每个键的后面都有个链,这样查找起来是费劲的,这个时候可以通过Rehash来进行完成,注意dict数据结构中的那个

dictht ht[2],这里是两个dictht,其中ht[1]是空闲的,在进行扩展的时候现将ht[1]扩展成ht[0]的两倍,然后将ht[0]中的键值对一个一个哈希到ht[1]中去,最后将ht[1]设置为ht[0]

这里需要注意的是rehash的时机,一般是负载因子大于5的时候扩展,负载因子小于0.1的时候收缩,还有一个问题是字典中有个属性是rehashidx,这个属性标志rehash的状态,如果是0,表示rehash正式开始,然后没rehash一个键值对,就将这个值加一,当ht[0]的值全部被转移到ht[1]的时候,就将这个值设置成-1,表示rehash操作完成。

其实还有很多要说的,比如渐进式rehash,渐进式就说说rehash过程不是一次性完成的,而是分多次,渐进式完成的,在rehash过程中,所有的删除,查找,更新都会在两个哈希表中进行,例如,如果查找一个元素,ht[0]中没有,那么就去ht[1]中查找,新添加的一律都是添加到ht[1]中,ht[0]中不再进行任何添加操作

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-09 19:53:32

Redis_字典的相关文章

redis中关于过期键的删除策略

我们已经了解到了Redis是一种内存数据库,Redis中数据都是以key-value的形式存储在内存中,由Redis服务器来维护和管理这部分内存,内存是何足珍贵,不需要的数据或者是已经使用过的没用的数据是不会让它长久的存在于内存中的,毕竟我们还是要建设节约型社会的.所以我们可以通过给键设置生存时间或者过期时间来权衡有限的内存和不断增长的数据,设置过期时间的命令为:[expire key 时间长度(秒)]或者是[pexpire key 时间长度(毫秒)] 同时也可以通过[expireat key

python--15 字典:当索引不好用

字典是python唯一的影射类型 hash >>> brand = ['李宁', '耐克', '阿迪达斯'] >>> slogan = ['一切皆有可能', 'Just do it','Impossible is nothing'] >>> print('李宁的口号是:',slogan[brand.index('李宁')]) 李宁的口号是: 一切皆有可能 字典不是序列类型 ,是映射类型 字符串 列表 元组是序列类型 创建和访问索引   标志性符号--花

如何通过字典表来获取下拉数据的实现

①在web.xml中添加监听,启动的时候初始化. <!--Web ApplicationContext 载入,继承处Spring的ApplicationContextListener --> <listener> <listener-class>cn.sccl.common.web.StartupListener</listener-class> </listener> ②我们需要在启动Tomcat的时候,初始化bizCode数据 package

字典及其方法

常用操作: 索引 get,has_key, 新增 setdefalt,update, 删除 pop,popitem,clear 键.值.键值对 items,values,values 循环  for i in info: print(i,info[i])for k,v in info.items(): print(k,v) 长度 len 字典方法 dic.clear() #删除字典中所有项 dic.copy() #复制列表中所有项 dic.fromkeys(S[,v]) #新建字典,键为S,值为

SQL Server2005+、MySQL、Oracle 数据库字典生成工具

之前找的数据库字典生成工具基本上都依赖于 Office Com 组件,在不安装 Office的情况下无法使用.怒,于是自己用C# 写了一个. 特征如下:    一.支持的数据库 MS SQL Server 2005+.My Sql.Oracle    二.支持的文档类型 Html.CHM.Docx    三.无需安装Office即可生成 Docx 格式的Word文件    四.基于 .net framework 3.5 框架,电脑上需要安装 .net framework 3.5.       

python基础:python循环、三元运算、字典、文件操作

目录: python循环 三元运算 字符串 字典 文件操作基础 一.python编程 在面向过程式编程语言的执行流程中包含: 顺序执行 选择执行 循环执行 if是条件判断语句:if的执行流程属于选择执行:if语句有三种格式,如下: 在多分支的if表达式中,即使多个条件同时为真,也只会执行一个,首先测试为真: 选择执行 单分支的if语句 if CONDITION: 条件为真分支 双分支的if语句 if CONDITION 条件为真分支 else 条件不满足时分支 多分支的if语句 if CONDI

按照字典排序

按照字典排序, 按照字典的value排序,类似sort -k命令 import operator x = {1:2,3:4, 4:3, 2:1, 0:0} sorted x =sorted(x.iteritems(), key = operator.itemgetter(1)) 0表示根据key排序,1表示根据value排序 In [33]: sorted(x.iteritems(),key=operator.itemgetter(0))                             

hdu 1251 统计难题(字典树)

Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀). Input 输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串. 注意:本题只有一组测试数据,处理到文件结束. Output 对于每个提

bing的简单英文字典工具

今天看到园友心白水撰写的<简单翻译工具--必应字典第三方API使用方法>,感觉很不错,所以用Python也写了一个.源码如下: 1 import urllib.request 2 import json 3 4 serviceurl='http://xtk.azurewebsites.net/BingDictService.aspx?Word=' 5 6 while True: 7 word = input('请输入英文单词: ') 8 if len(word) < 1 : 9 brea