理解 redis 中的 哈希对象类型

redis中的hash也是我们使用中的高频数据结构,它的构造基本上和编程语言中的HashTable,Dictionary大同小异,如果大家往后有什么逻辑需要用Dictionary存放的话,可以根据场景优先考虑下redis哦,起码可以装装嘛,现在我默认你已经有装的冲动了,打开redis手册,看看有哪些我们用得到的装方法。

一:常用方法

只要是一个数据结构,最基础的永远是CURD,redis中的insert和update,永远只需要set来替代,比如下面的Hset,如下图:

前面几篇文章我都没有挑选一个方法仔细讲解,其实也没什么好讲解的,就好似C#中的一个类的一个方法而已,知道传递一些啥参数就OK了,就比如要说的HSet,它的格式如下:

接下来我在CentOS里面操作一下,


[administrator@localhost redis-3.0.5]$ src/redis-cli
127.0.0.1:6379> clear127.0.0.1:6379> hset person name jack
(integer) 1
127.0.0.1:6379> hset person age 20
(integer) 1
127.0.0.1:6379> hset person sex famale
(integer) 1
127.0.0.1:6379> hgetall person
1) "name"
2) "jack"
3) "age"
4) "20"
5) "sex"
6) "famale"
127.0.0.1:6379> hkeys person
1) "name"
2) "age"
3) "sex"
127.0.0.1:6379> hvals person
1) "jack"
2) "20"
3) "famale"
127.0.0.1:6379>

或许有人看了上面的console有一点疑惑,那就是前面有几个参数,比如person,name啦,然后才是value,如果你看了第一篇的话,你大概就明白了,其实在redis的这个层面,它永远只有一个键,一个值,这个键永远都是字符串对象,也就是SDS对象,而值的种类就多了,有字符串对象,有队列对象,还有这篇的hash对象,往后的有序集合对象等等,如果你还不明白的话,转化为C#语言就是。


var person=new Dictionary<string,string>();
person.Add("name","jack");
...

调用方法就是这么的简单,关键在于时不时的需要你看一看手册,其实最重要的是了解下它在redis源码中的原理就好了。

二:探索原理

hash的源代码是在 dict.h 文件下,枚举如下:


typedef struct dictEntry {void *key;union {void *val;uint64_t u64;int64_t s64;double d;} v;struct dictEntry *next;
} dictEntry;typedef struct dictType {unsigned int (*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;/* This is our hash table structure. Every dictionary has two of this as we* implement incremental rehashing, for the old to the new 0. */
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 */int iterators; /* number of iterators currently running */
} dict;/* If safe is set to 1 this is a safe iterator, that means, you can call* dictAdd, dictFind, and other functions against the dictionary even while* iterating. Otherwise it is a non safe iterator, and only dictNext()* should be called while iterating. */
typedef struct dictIterator {dict *d;long index;int table, safe;dictEntry *entry, *nextEntry;/* unsafe iterator fingerprint for misuse detection. */long long fingerprint;
} dictIterator;

上面就是我们使用hash的源代码数据结构,接下来我来撸一撸其中的逻辑关系。

1. 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;

这个结构是hash的真正的底层数据结构,可以看到其中有5个属性。

  • dictType *type

可以看到它的类型是dictType,从上面你也可以看到,它是有枚举结构定义的,如下:


typedef struct dictType {unsigned int (*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;

从上面这个数据结构中你可以看到里面都是一些方法,但是有一个非常重要的方法,那就是第一个hashFunction,可以看到它就是计算hash值的,跟C#中的dictionary中求hash值一样一样的。

  • dictht ht[2]

你可能会疑问,为什么这个属性是2个大小的数组呢,其实正真使用的是 ht[0],而ht[1]是用于扩容hash表时的暂存数组,这一点也很奇葩,同时也很精妙,redis为什么会这么做呢???仔细想想你可能会明白,扩容有两种方法,要么一次性扩容,要么渐进性扩容,后面这种扩容是什么意思呢?就是我在扩容的同时不影响前端的CURD,我慢慢的把数据从ht[0]转移到ht[1]中,同时rehashindex来记录转移的情况,当全部转移完成之后,将ht[1]改成ht[0]使用,就这么简单。

2. dicth结构


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

从上面这个结构体中,你可以看到一个非常重要的属性:dictEntry **table, 其中table是一个数组,数组类型是dictEntry,既然是一个数组,那后面的三个属性就好理解了,size是数组的大小,sizemask和数组求模有关,used记录数组中已使用的大小,现在我们把注意力放在dictEntry这个数组实体类型上面。

3. dictEntry结构


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

从这个数据结构上面你可以看到有三个大属性。

第一个就是:*key:它就是hash表中的key。

第二个就是:union的*val 就是hash的value。

第三个就是:*next就是为了防止hash冲突采用的挂链手段。

这个原理和C#中的Dictionary还是一样一样的。

不知道你看懂了没有,如果总结上面描述的话,我可以画出如下的hash结构图。

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

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

相关文章

java实用教程——组件及事件处理——DocumentEvent事件

DocumentEvent事件源&#xff1a; 文本区Document的维护 注册监视器&#xff1a; 使用addDocumentListener(DocumentListener listen)为事件源添加监视器 DocumentListener接口&#xff1a; 接口中有三个方法&#xff1a; public void changUpdate(DocumentEvent e); public vo…

prometheus-net.DotNetRuntime 获取 CLR 指标原理解析

prometheus-net.DotNetRuntime 介绍Intro前面集成 Prometheus 的文章中简单提到过&#xff0c;prometheus-net.DotNetRuntime 可以获取到一些 CLR 的数据&#xff0c;比如说 GC, ThreadPool, Contention, JIT 等指标&#xff0c;而这些指标可以很大程度上帮助我们解决很多问题&…

错误代码1500什么意思_啊早安打工人是什么梗???

早安打工人是什么梗&#xff1f;最近打工人这个词成为了大家口中最为常见的一个词语&#xff0c;打工人的爆火也引起了很多人的关注&#xff0c;这样一个词语在很多人看来很有可能还有点嘲讽的含义&#xff0c;却突然火遍全网&#xff0c;究竟打工人是什么梗&#xff1f;看起来…

java实用教程——组件及事件处理——MouseEvent事件

MouseEvent事件 任何组件上都可以发生鼠标事件&#xff0c;如鼠标进入组件、退出组件、在组件上方单击鼠标、拖动鼠标等都触发鼠标事件&#xff0c;即导致MouseEvent类自动创建一个 事件对象&#xff0c;事件源注册监视器的方法是addMouseListener(MouseListener listener); …

这个世界,正在悄悄惩罚那些不注意身体的人

这是头哥侃码的第226篇原创上周四&#xff0c;整个网络被 “马拉多纳去世” 的消息刷屏了。虽然我从不看足球&#xff0c;而且没有看过马拉多纳踢球&#xff0c;但关于他的故事、他的传奇、他的丰功伟绩&#xff0c;倒是听过不少。所以在听到这个消息的时候&#xff0c;我感到深…

tcp拥塞控制_网络TCP的拥塞控制算法简介

作为网络中使用最广泛的传输协议&#xff0c;TCP的拥塞控制机制是学术界和工业界关注的焦点问题之。然而&#xff0c;目前广泛使用的TCP传输协议的拥塞控制算法仍然使用相对固定的窗口调节策略&#xff0c;无法根据动态变化的场景自适应地调整参数&#xff0c;从而造成不可避免…

java实用教程——组件及事件处理——对话框(消息对话框,输入对话框,确认对话框)

消息对话框&#xff1a;(这个对话框提供一些信息) 无模式&#xff1a;可多线程的执行 有模式&#xff1a;用户必须处理这个一个对话框。必须解决这个问题后才可以继续相处下去 对话框分为无模式和有模式两种。如果一个对话框 是有模式的对话框&#xff0c;那么当这个对话框处于…

11张图演进SeviceMesh服务网格

本周和大家聊聊架构进化史-大家可文末扫码加入随着互联网持续高歌猛进&#xff0c;相关技术名词也是层出不穷&#xff0c;ServiceMesh服务网格这两年尤为火爆&#xff0c;然而很少有讲清楚的文章。笔者这里用心整理了一篇文章&#xff0c;用11张图演绎ServiceMesh的进化历程&am…

java实用教程——组件及事件处理——对话框(颜色对话框,自定义对话框)

颜色对话框&#xff1a; 可以用javax.swing包中的JColorChooser类的静态方法 public staticColorshowDialog (Component component, String title, Color initialColor) 创建一个有模式的颜色对话框&#xff0c;其中参数component指定颜色对话框可见时的位置&#xff0c;颜色对…

.NET Core/.NET 5.0 析构函数依然有效?

【导读】最近看到小伙伴在.NET Core中用到了析构函数&#xff0c;不禁打一疑问&#xff0c;大部分情况下&#xff0c;即使在.NET Framework中都不会怎么用到析构函数&#xff0c;我想在.NET Core中是否还依然有效呢&#xff1f;随着时间推移&#xff0c;迭代版本更新&#xff0…

java实用教程——常用实用类——String类(字符串类)

JAVA把String类定义为final类(因此用户不能扩展String类&#xff0c;即String类不可以有子类) String对象可以用""进行并置运算 identityHashCode会返回对象的hashCode&#xff0c;而不管对象是否重写了hashCode方法。 public class Example8_1 {public static void…

sqlserver 事务日志 异常增长原因排查_小白入门学习打日志

前言只有光头才能变强。文本已收录至我的GitHub仓库&#xff0c;欢迎Star&#xff1a;https://github.com/ZhongFuCheng3y/3y记得之前写过一篇&#xff1a;《阿里巴巴 Java开发手册》读后感&#xff0c;之前自学时由于没怎么接触过打“日志”&#xff0c;所以《手册》中的“日志…

在 k8s 中部署 Prometheus 和 Grafana

部署 Prometheus 和 Grafana 到 k8sIntro上次我们主要分享了 asp.net core 集成 prometheus&#xff0c;以及简单的 prometheus 使用&#xff0c;在实际在 k8s 中部署的时候就不能在使用前面讲的静态配置的方式来部署了&#xff0c;需要使用 Prometheus 的服务发现。部署规划Pr…

EntityFramework Core 5.0 VS SQLBulkCopy

【导读】EF Core 5.0伴随着.NET 5.0发布已有一段时日&#xff0c;本节我们来预估当大批量新增数据时&#xff0c;大概是多少区间我们应该考虑SQLBulkCopy而不是EF CoreSQLBulkCopy早出现于.NET Framework 2.0&#xff0c;将数据批量写入利用此类毫无疑问最佳&#xff0c;虽其来…

小心使用 Task.Run 续篇

关于前两天发布的文章&#xff1a;为什么要小心使用 Task.Run&#xff0c;对文中演示的示例到底会不会导致内存泄露&#xff0c;给很多人带来了疑惑。这点我必须向大家道歉&#xff0c;是我对导致内存泄漏的原因没描述和解释清楚&#xff0c;也没用实际的示例证实&#xff0c;是…

java实用教程——组件及事件处理——设置组件的位置(相对于窗口具体位置和布局)

1&#xff1a; 相对于窗口的具体位置 关键点&#xff1a; JButton组件添加到JPanel时&#xff0c;如果想自己位置&#xff0c;需要对JPanel进行如下设置&#xff0c;才能自定义按钮位置 需要将组件添加到画板上去&#xff0c;才可以设置组件的相对具体位置 button1.setBounds…

usb接口定义引脚说明_PerfDogService使用说明

令牌申请教程&#xff1a;https://bbs.perfdog.qq.com/article-detail.html?id55安装包下载&#xff1a;https://perfdog.qq.com/sdk一、 概述PerfDog性能狗服务组件&#xff0c;用户可基于service组件二次开发自己PerfDog性能工具或自动化服务。本文档主要对PerfDogService提…

java实用教程——组件及事件处理——布局管理(五种)

1.流式布局FlowLayout public void pack()调整此窗口的大小&#xff0c;以适合其子组件的首选大小和布局。如果该窗口或其所有者仍不可显示&#xff0c;则两者在计算首选大小之前变得可显示。在计算首选大小之后&#xff0c;将会验证该Window。窗口自动适应大小&#xff0c;使…

个人博客前端模板_腾讯前端开发工程师,教你极速搭建一个个人博客网站

作者&#xff1a; bookerzhao&#xff0c;腾讯 CSIG web前端开发工程师Github 为开源项目提供了用于静态页面展示的 Pages 服务&#xff0c;很多开发者都在上面托管了自己的静态网站和博客&#xff0c;不少开源项目的案例和文档页面也采用了这种方式。不过由于 Pages 的 CDN 节…

云原生时代 给予.NET的机会

.NET诞生于与Java的竞争&#xff0c;微软当年被罚款20亿美元。Java绝不仅仅是一种语言&#xff0c;它是COM的替代者&#xff01;而COM恰恰是Windows的编程模型。而Java编程很多时候比C编程要容易的多&#xff0c;更致命的是他是跨平台的。微软所推行.NET战略&#xff0c;并且C#…