Redis入门到通关之数据结构解析-动态字符串SDS

2024-04-23 08:52

本文主要是介绍Redis入门到通关之数据结构解析-动态字符串SDS,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • Redis数据结构-动态字符串
  • 动态扩容举例
  • 二进制安全
  • SDS优点
  • 与C语言中的字符串的区别


在这里插入图片描述

欢迎来到 请回答1024 的博客

🍓🍓🍓欢迎来到 请回答1024的博客

关于博主: 我是 请回答1024,一个追求数学与计算的边界、时间与空间的平衡,0与1的延伸的后端开发者。

博客特色: 在我的博客中,开设了如下专栏(点击可以进入专栏奥~): Java、MySQL、Redis、Spring、SpringBoot、SpringCloud、RabbitMQ、微服务、分布式 等相关技术专栏。期待与您一起,探索编程世界中的发现和创新之旅。

🍎🍎🍎我的主页 : https://reply1024.blog.csdn.net

敬请期待定期更新、见解和教程!让我们一起踏上这段编码冒险之旅!

数学与计算的边界 时间与空间的平衡 0与1的延伸


Redis数据结构-动态字符串

我们都知道 Redis 中保存的Key是字符串,value 往往是字符串或者字符串的集合。可见字符串是 Redis 中最常用的一种数据结构。

不过 Redis 没有直接使用C语言中的字符串,因为C语言字符串存在很多问题:

  • 获取字符串长度的需要通过运算

  • 非二进制安全

  • 不可修改

Redis 构建了一种新的字符串结构,称为简单动态字符串(Simple Dynamic String),简称 SDS
例如,我们执行命令:

set name 技术

那么 Redis 将在底层创建两个 SDS,其中一个是包含“name”的 SDS,另一个是包含“技术”的 SDS。

Redis 是 C 语言实现的,其中 SDS 是一个结构体,源码如下:

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct sds {int len;         // 记录字符串的长度int free;        // 记录未使用的字节数char buf[];      // 字符串的实际存储空间
} sds;// 创建一个新的 sds
sds *sds_new(int init_len) {sds *s = malloc(sizeof(sds) + init_len + 1);if (!s) return NULL;s->len = 0;s->free = init_len;s->buf[0] = '\0';return s;
}// 释放 sds
void sds_free(sds *s) {if (s) free(s);
}// 追加字符串到 sds
sds *sds_append(sds *s, const char *append) {int append_len = strlen(append);if (s->free < append_len) {s = realloc(s, sizeof(sds) + s->len + append_len + 1);if (!s) return NULL;s->free = append_len;}memcpy(s->buf + s->len, append, append_len);s->len += append_len;s->free -= append_len;s->buf[s->len] = '\0';return s;
}// 打印 sds
void sds_print(const sds *s) {printf("Length: %d\n", s->len);printf("Free: %d\n", s->free);printf("String: %s\n", s->buf);
}int main() {sds *str = sds_new(10);if (!str) {printf("Error: Unable to create SDS.\n");return 1;}str = sds_append(str, "Hello, ");if (!str) {printf("Error: Unable to append to SDS.\n");return 1;}str = sds_append(str, "world!");if (!str) {printf("Error: Unable to append to SDS.\n");return 1;}sds_print(str);sds_free(str);return 0;
}

例如,一个包含字符串“name”的sds结构如下:

在这里插入图片描述


动态扩容举例

SDS 之所以叫做动态字符串,是因为它具备动态扩容的能力,例如一个内容为“hi”的SDS:

在这里插入图片描述

假如我们要给SDS追加一段字符串“,Amy”,这里首先会申请新内存空间:

  • 如果新字符串小于1M,则新空间为扩展后字符串长度的两倍+1;

  • 如果新字符串大于1M,则新空间为扩展后字符串长度+1M+1。称为内存预分配
    在这里插入图片描述

二进制安全

  • Redis 可以存储各种数据类型,那么二进制数据肯定也不例外。但二进制数据并不是规则的字符串格式,可能会包含一些特殊的字符,比如 ‘\0’ 等。
  • 前面我们提到过,C 中字符串遇到 ‘\0’ 会结束,那 ‘\0’ 之后的数据就读取不上了。但在 SDS 中,是根据 len 长度来判断字符串结束的。
  • 如此, 二进制安全的问题就解决了。

SDS优点

SDS 优点:

  1. 获取字符串长度的时间复杂度为O(1)
  2. 支持动态扩容, 减少内存分配次数
  3. 二进制安全

与C语言中的字符串的区别

SDS(Simple Dynamic String)是Redis使用的一种字符串表示方式,与C语言中的字符串有一些显著的区别:

  • 动态调整大小:SDS是动态分配内存的,可以根据需要动态增加或减少其大小,而C语言中的字符串通常是静态分配的,大小在创建时就确定了,后续无法直接调整大小。

  • 二进制安全:SDS允许存储任意二进制数据,而C语言中的字符串通常以NULL结尾,因此不适合存储包含NULL字符的二进制数据。

  • 惰性空间释放:SDS采用惰性空间释放策略,即当SDS的内容被截断或缩短时,并不立即释放多余的内存,而是等待下一次需要扩展空间时才释放。这种策略可以减少频繁的内存分配和释放操作,提高性能。而C语言中的字符串在缩短时无法自动释放多余的内存,需要手动管理内存。

  • 长度存储:SDS在内部存储了字符串的长度信息,这样可以在O(1)时间内获取字符串的长度,而C语言中的字符串需要遍历整个字符串才能确定长度。

SDS是一种更加灵活和高效的字符串表示方式,特别适合需要频繁修改和操作字符串的场景,而C语言中的字符串更适合于静态不变的情况。


在这里插入图片描述


这篇关于Redis入门到通关之数据结构解析-动态字符串SDS的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/928333

相关文章

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Redis 热 key 和大 key 问题小结

《Redis热key和大key问题小结》:本文主要介绍Redis热key和大key问题小结,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、什么是 Redis 热 key?热 key(Hot Key)定义: 热 key 常见表现:热 key 的风险:二、

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

Golang HashMap实现原理解析

《GolangHashMap实现原理解析》HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,:本文主要介绍GolangH... 目录HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持

SpringBoot基于配置实现短信服务策略的动态切换

《SpringBoot基于配置实现短信服务策略的动态切换》这篇文章主要为大家详细介绍了SpringBoot在接入多个短信服务商(如阿里云、腾讯云、华为云)后,如何根据配置或环境切换使用不同的服务商,需... 目录目标功能示例配置(application.yml)配置类绑定短信发送策略接口示例:阿里云 & 腾

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自