iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >简单动态字符串(simple dynamic string)SDS
  • 906
分享到

简单动态字符串(simple dynamic string)SDS

2023-06-02 14:06:13 906人浏览 八月长安
摘要

Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string SDS)的抽象类型,并将SDS用作Redis 的默认字符串表示:10.143.128.165:6379>

Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string SDS)的抽象类型,并将SDS用作Redis 的默认字符串表示:

10.143.128.165:6379> SET msg "hello world"OK

设置一个key= msg,value = hello world 的新键值对,

键(key)是一个字符串对象,对象的底层实现是一个保存着字符串“msg” 的SDS;

值(value)也是一个字符串对象,对象的底层实现是一个保存着字符串“hello world” 的SDS

SDS除了用来保存字符串以外,SDS还被用作缓冲区(buffer)AOF模块中的AOF缓冲区。

SDS 的定义

Redis 中定义动态字符串的结构:

  struct sdshdr {           int len;// buf 中已占用空间的长度          int free;// buf 中剩余可用空间的长度        char buf[];// 数据空间  };

简单动态字符串(simple dynamic string)SDS

len 变量,用于记录buf 中已经使用的空间长度(这里指出Redis 的长度为5)

free 变量,用于记录buf 中还空余的空间(初次分配空间,一般没有空余,在对字符串修改的时候,会有剩余空间出现)

buf 字符数组,用于记录我们的字符串(记录Redis)

SDS 与 C 字符串的区别

C 字符串SDS
获取字符串长度的复杂度为O(N)获取字符串长度的复杂度为O(1)
api 是不安全的,可能会造成缓冲区溢出API 是安全的,不会造成缓冲区溢出
修改字符串长度N次必然需要执行N次内存重分配修改字符串长度N次最多执行N次内存重分配
只能保存文本数据可以保存二进制数据和文本文数据
可以使用所有<String.h>库中的函数可以使用一部分<string.h>库中的函数

1 获取字符串长度(SDS O(1)/C 字符串 O(n))

传统的C 字符串 使用长度为N+1 的字符串数组来表示长度为N 的字符串,所以为了获取一个长度为C字符串的长度,必须遍历整个字符串。

SDS 的数据结构中,有专门用于保存字符串长度的变量,可以通过获取len 属性的值,直接知道字符串长度。

简单动态字符串(simple dynamic string)SDS

2 杜绝缓冲区溢出

C 字符串 不记录字符串长度,除了获取的时候复杂度高以外,还容易导致缓冲区溢出。

假设程序中有两个在内存中紧邻着的 字符串 s1 和 s2,其中s1 保存了字符串“redis”,二s2 则保存了字符串“MongoDb”:

简单动态字符串(simple dynamic string)SDS

如果我们现在将s1 的内容修改为redis cluster,但是又忘了重新为s1 分配足够的空间,这时候就会出现以下问题:

简单动态字符串(simple dynamic string)SDS

原本s2 中的内容已经被S1的内容给占领了,s2 现在为 cluster,而不是“mongoDB”。

当需要对一个SDS 进行修改的时候,redis 会在执行拼接操作之前,预先检查给定SDS 空间是否足够,如果不够,会先拓展SDS 的空间,然后再执行拼接操作:

简单动态字符串(simple dynamic string)SDS简单动态字符串(simple dynamic string)SDS

3 减少修改字符串时带来的内存重分配次数

C语言字符串在进行字符串的扩充和收缩的时候,都会面临着内存空间的重新分配问题。

字符串拼接会产生字符串的内存空间的扩充,在拼接的过程中,原来的字符串的大小很可能小于拼接后的字符串的大小,那么这样的话,就会导致一旦忘记申请分配空间,就会导致内存的溢出。

字符串在进行收缩的时候,内存空间会相应的收缩,而如果在进行字符串的切割的时候,没有对内存的空间进行一个重新分配,那么这部分多出来的空间就成为了内存泄露。

我们需要对下面的SDS进行拓展,则需要进行空间的拓展,这时候redis 会将SDS的长度修改为13字节,并且将未使用空间同样修改为1字节

简单动态字符串(simple dynamic string)SDS简单动态字符串(simple dynamic string)SDS 

因为在上一次修改字符串的时候已经拓展了空间,再次进行修改字符串的时候会发现空间足够使用,因此无须进行空间拓展

简单动态字符串(simple dynamic string)SDS

通过这种预分配策略,SDS将连续增长N次字符串所需的内存重分配次数从必定N次降低为最多N次

4 惰性空间释放

SDS 的free 属性,是用于记录空余空间的。除了在拓展字符串的时候会使用到free 来进行记录空余空间以外,在对字符串进行收缩的时候,也可以使用free 属性来进行记录剩余空间,避免下次对字符串进行再次修改的时候,需要对字符串的空间进行拓展。

SDS 提供了相应的API,可以在有需要的时候,自行释放SDS 的空余空间。

通过惰性空间释放,SDS 避免了缩短字符串时所需的内存重分配操作,并未将来可能有的增长操作提供了优化

5 二进制安全

C 字符串中的字符必须符合某种编码,并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,而不能保存想图片,音频,视频,压缩文件这样的二进制数据。

Redis 不是靠空字符来判断字符串的结束的,而是通过len这个属性。

简单动态字符串(simple dynamic string)SDS

6 兼容部分C字符串函数

虽然SDS 的API 都是二进制安全的,但一样遵循C字符串以空字符串结尾的惯例。

========================================================================

链表

链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度。

Redis 中 列表键的底层实现之一就是链表。当一个列表键包含了数量较多的元素,又或者列表中包含的元素都是比较长的字符串时,Redis 就会使用链表作为列表键的底层实现。

每个链表节点使用一个 listnode结构表示:

typedef struct listNode{      struct listNode *prev;      struct listNode * next;      void * value;  }

多个链表节点组成的双端链表:

简单动态字符串(simple dynamic string)SDS

list:

typedef struct list{       listNode  * head;//表头节点      listNode  * tail;//表尾节点       unsigned long len;//链表长度       void *(*dup) (void *ptr);//节点值复制函数     void (*free) (void *ptr);//节点值释放函数     int (*match)(void *ptr, void *key);//节点值对比函数}

简单动态字符串(simple dynamic string)SDS

链表的特性

  • 双端:链表节点带有prev 和next 指针,获取某个节点的前置节点和后置节点的时间复杂度都是O(N)
  • 无环:表头节点的 prev 指针和表尾节点的next 都指向NULL,对立案表的访问时以NULL为截止
  • 表头和表尾:因为链表带有head指针和tail 指针,获取链表头结点和尾节点的时间复杂度为O(1)
  • 长度计数器:链表中存有记录链表长度的属性 len
  • 多态:链表节点使用 void* 指针来保存节点值,并且可以通过list 结构的dup 、 free、 match三个属性为节点值设置类型特定函数。

========================================================================

字典

字典,又称为符号表(symbol table)、关联数组(associative array)或映射(map),是一种用于保存键值对的抽象数据结构。 

在字典中,一个键(key)可以和一个值(value)进行关联,字典中的每个键都是独一无二的。在C语言中,并没有这种数据结构,但是Redis 中构建了自己的字典实现。

10.143.128.165:6379> SET msg "hello world"OK

字典的定义

1 哈希表

Redis 字典所使用的哈希表由 dict.h/dictht 结构定义:

typedef struct dictht {     dictEntry **table; //哈希表数组     unsigned long size;//哈希表大小      unsigned long sizemask;//哈希表大小掩码,用于计算索引值     unsigned long used;//该哈希表已有节点的数量}

一个空的字典的结构图如下:

简单动态字符串(simple dynamic string)SDS

在结构中存有指向dictEntry 数组的指针,而我们用来存储数据的空间就是 dictEntry

 2. 哈希表节点( dictEntry )
typeof struct dictEntry{   void *key; //键   uNIOn{   //值      void *val;      uint64_tu64;      int64_ts64;   }   struct dictEntry *next;}

在数据结构中,key 是唯一的,但是存入里面的key 并不是直接的字符串,而是一个hash 值,通过hash 算法,将字符串转换成对应的hash 值,然后在dictEntry 中找到对应的位置。

如果出现hash 值相同的情况,Redis 采用了链地址法:

简单动态字符串(simple dynamic string)SDS

当k1 和k0 的hash 值相同时,将k1中的next 指向k0 形成一个链表。

3 字典
typedef struct dict {      dictType *type;  // 类型特定函数        void *privedata; // 私有数据       dictht  ht[2];  // 哈希表      in trehashidx; // rehash 索引}

type 属性 和privdata 属性是针对不同类型的键值对,为创建多态字典而设置的。

ht 属性是一个包含两个项(两个哈希表)的数组

普通状态下的字典:

简单动态字符串(simple dynamic string)SDS

解决哈希冲突

在插入一条新的数据时,会进行哈希值的计算,如果出现了hash值相同的情况,Redis 中采用了连地址法(separate chaining)来解决键冲突。每个哈希表节点都有一个next 指针,多个哈希表节点可以使用next 构成一个单向链表,被分配到同一个索引上的多个节点可以使用这个单向链表连接起来解决hash值冲突的问题。

简单动态字符串(simple dynamic string)SDS

 现在要插入k2,通过hash 算法计算到k2 的hash 值为2,即需要将k2 插入到dictEntry[2]中:

简单动态字符串(simple dynamic string)SDS

--结束END--

本文标题: 简单动态字符串(simple dynamic string)SDS

本文链接: https://www.lsjlt.com/news/230237.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 简单动态字符串(simple dynamic string)SDS
    Redis 没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string SDS)的抽象类型,并将SDS用作Redis 的默认字符串表示:10.143.128.165:6379>...
    99+
    2023-06-02
  • Redis中SDS简单动态字符串详解
    Redis 是内存数据库,高效使用内存对 Redis 的实现来说非常重要。 看一下,Redis 中针对字符串结构针对内存使用效率做的设计优化。 一、SDS的结构  C语言没有string类型,本质是char[...
    99+
    2023-04-12
    redis sds 介绍 redis sds原理 Redis的SDS结构
  • Redis中SDS简单动态字符串问题怎么解决
    这篇文章主要介绍“Redis中SDS简单动态字符串问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Redis中SDS简单动态字符串问题怎么解决”文章能帮助大家解决问题。一、SDS的结构&n...
    99+
    2023-07-06
  • 解析Redis数据结构之简单动态字符串sds
    Redis是用ANSI C语言编写的,它是一个高性能的key-value数据库,它可以作用在数据库、缓存和消息中间件。其中 Redis 键值对中的键都是 string 类型,而键值对...
    99+
    2024-04-02
  • 几分钟教你掌握Redis简单动态字符串SDS
    目录正文redisLog(REDIS_WARNING,"Redis is now ready to exit, bye bye...");与C字符串的区别获取字符...
    99+
    2023-01-28
    Redis动态字符串SDS Redis SDS
  • redis内部数据结构之SDS简单动态字符串的示例分析
    小编给大家分享一下redis内部数据结构之SDS简单动态字符串的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言rei...
    99+
    2024-04-02
  • Redis数据结构的动态字符串sds怎么使用
    本篇内容主要讲解“Redis数据结构的动态字符串sds怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis数据结构的动态字符串sds怎么使用”吧!Redis是用ANSI C语言编写的...
    99+
    2023-06-21
  • Python格式化字符串f-string简介
    目录简介用法简单使用表达式求值与函数调用引号、大括号与反斜杠多行f-string综合示例lambda表达式简介 f-string,亦称为格式化字符串常量(formatted stri...
    99+
    2022-12-19
    Python格式化字符串f-string Python格式化字符串 Python字符串f-string
  • Java将String字符串带括号转成List的简单方法
    目录问题现象解决问题 附:Java 字符串或字符串数组转为 List总结问题现象 今天在做一个需求:将存入数据库中的数据读到后解析成list遍历分析 数据格式: "...
    99+
    2023-03-06
    java将字符串转list java中string转为list string转list
  • Python的字符串操作简单实例
    目录实例1:获取星期字符串实例2:获取月份字符串实例3:恺撒密码实例1:获取星期字符串 程序读入一个表示星期几的数字(1~7),输出对应的星期字符串名称。例如,输入 3,返回&ldq...
    99+
    2023-05-15
    Python字符串 Python字符串操作
  • C#实现简单的字符串加密
    最近用到一些字符串加密,而.net中提供的加密算法中用起来比较复杂,便简单的封装了一下,方便日后使用。 public class Encrypt { ...
    99+
    2024-04-02
  • python字符串怎么实现简单运算
    这篇文章将为大家详细讲解有关python字符串怎么实现简单运算,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。python的数据类型有哪些python的数据类型:1. 数字类型,包括int(整型)、long...
    99+
    2023-06-14
  • python字符串简单加密怎么实现
    可以使用简单的凯撒密码来对字符串进行加密。以下是一个使用凯撒密码实现字符串加密和解密的示例代码: def encrypt(text,...
    99+
    2024-04-08
    python
  • 简单聊聊C#字符串构建利器StringBuilder
    目录前言简单示例源码探究构造入手无参构造带参数的构造构造小结核心方法转换成字符串对比java实现总结前言 在日常的开发中StringBuilder大家肯定都有用过,甚至用的很多。毕竟...
    99+
    2024-04-02
  • 怎么进行java字符串的简单介绍
    本篇文章给大家分享的是有关怎么进行java字符串的简单介绍,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。java字符串你可能注意到了,在前面关于数据类型和数组的讨论中没有提到字...
    99+
    2023-06-03
  • Python截取字符串的简单方法实例
    目录前言模版示例获取字符串的前 5 个字符获取从第 3 个字符开始,长度为 4 的截取字符串获取字符串的最后一个字符获取字符串的末尾 5 个字符获取一个截取字符串,包括除了末尾 4 ...
    99+
    2024-04-02
  • PHP 判断字符串中文和数字的简单实现
    PHP是一种被广泛应用的服务器端脚本语言,具有灵活、强大和易学的特点。在使用PHP进行字符串处理的过程中,判断字符串中是否包含中文和数字是一种常见需求。本文将介绍如何在PHP中实现简单...
    99+
    2024-03-08
    php 字符串 判断
  • Go简单字符串插值特性实例分析
    这篇文章主要讲解了“Go简单字符串插值特性实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Go简单字符串插值特性实例分析”吧!fmt.Printf 或 fmt.Sp...
    99+
    2023-07-05
  • Linux下实现 OpenSSL 简单加密与解密字符串
    场景shell脚本中存在明文密码客户要求禁止使用明文密码,密码做加密处理.方案在网上了解到了Linux OpenSSL加密解密工具可以指定各种加密算法为字符,文件做加密处理.加密的案例比较多,解密的寥寥无几.有兴趣的可以去查下中文...
    99+
    2023-06-05
  • 利用Rust编写一个简单的字符串时钟
    目录1、简介2、用到的知识点2.1 取utc时间2.2 图片变换为像素图案2.3 字符方式显示当前时间2.4 时间刷新1、简介 用rust写的一个简单的练手的demo,一个字符串时钟...
    99+
    2022-12-26
    Rust字符串时钟 Rust 时钟
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作