Redis数据类型之字符串

Redis数据类型之字符串


redis的字符串

redis的字符串不是C语言原生的字符串,而是自己构建的称为简单动态字符串(simple dynamic string),简称 SDS,和C语言原生的字符串相似,使用’\0’作为结尾。

除了打印日志之外,我们操作字符串基本是在使用SDS

SDS的在redis的主要功能

 1. 保存数据库的字符串值
 2. 用作缓冲区buffer

SDS在redis的定义

在源码包下面的src目录下的sds.h 和sds.c

    typedef char *sds;
    /**
     * 保存字符串对象的结构
     */
    struct sdshdr {

        // buf 中已占用空间的长度
        int len;

        // buf 中剩余可用空间的长度
        int free;

        // 数据空间
        char buf[];
    };

为什么使用SDS而不是C语言原生的字符串?

SDS有一下特点

  1. 获取字符串长度的时间复杂度是O(1)

    C语言本省并不携带自身的长度属性,所以要获取长度必须要遍历一次,这个复杂度是O(n)

    /**
     * 返回实际的长度
     */
    static inline size_t sdslen(const sds s) {
        struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
        return sh->len;
    }
  1. 防止缓存区溢出

    这个由C语言的一些列不安全的字符串操作函数可以看出,比如

    strcat(char* dest,const char* src)

看看sds.c中的sdscat()

    //函数原型
    sds sdscat(sds s, const char *t);
    //具体实现
    sds sdscat(sds s, const char *t) {
        return sdscatlen(s, t, strlen(t));
    }
    //sdscatlen
    sds sdscatlen(sds s, const void *t, size_t len) {

        struct sdshdr *sh;

        // 原有字符串长度
        size_t curlen = sdslen(s);

        // 扩展 sds 空间
        // T = O(N)
        s = sdsMakeRoomFor(s,len);

        // 内存不足?直接返回
        if (s == NULL) return NULL;

        // 复制 t 中的内容到字符串后部
        // T = O(N)
        sh = (void*) (s-(sizeof(struct sdshdr)));
        memcpy(s+curlen, t, len);

        // 更新属性
        sh->len = curlen+len;
        sh->free = sh->free-len;

        // 添加新结尾符号
        s[curlen+len] = ‘\0‘;

        // 返回新 sds
        return s;
    }

可以看到,sds在进行拼接的时候,首先获取原字符串的长度,然后进行扩展。

3. 减少修改字符串时的内存重新分配

C语言的字符串的首先还是依靠字符数组,长度为N的字符串对应的是一个长度为N+1的字符数组,所以,在对字符串进行操作时,都会发生对字符数组的内存重新分配。

对于内存的重新分配,一般设计复杂的算法和系统调用,相对比较耗时,偶尔一次的重新分配还可以接受,但是对于redis,频繁的操作,肯定效率非常低下。

还记得sds的结构体么?保存了一个未使用的空间。sds通过这个来屏蔽了与底层数组的关联 。

那么sds如何使用这个free来实现减少内存重新分配?

方法一、内存预分配。 优化sds的增长操作

简单的说,就是redis API 在修改sds的时候,如果有涉及对sds长度进行扩展,那么,同时扩展sds的free空间长度。如果free足够,那么就使用free空间。

那么扩展多少?free与length又有什么大小关系?

- 如果扩展之后的sds小于1M,那么,扩展之后的free==length,总的内存大小是 free+length+1byte

- 如果扩展之后的sds大于于1M,那么,free的大小是1M,总长度是1M+length+1byte

方法二、惰性空间释放 优化sds的缩短操作

简单的说,就是redis API 在截断sds的时候,程序并不立即回收多出来的内存,而是使用free属性来保存这些空间。

实现代码

    sds sdstrim(sds s, const char *cset) {
    struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
    char *start, *end, *sp, *ep;
    size_t len;

    // 设置和记录指针
    sp = start = s;
    ep = end = s+sdslen(s)-1;

    // 修剪, T = O(N^2)
    while(sp <= end && strchr(cset, *sp)) sp++;
    while(ep > start && strchr(cset, *ep)) ep--;

    // 计算 trim 完毕之后剩余的字符串长度
    len = (sp > ep) ? 0 : ((ep-sp)+1);

    // 如果有需要,前移字符串内容
    // T = O(N)
    if (sh->buf != sp) memmove(sh->buf, sp, len);

    // 添加终结符
    sh->buf[len] = ‘\0‘;

    // 更新属性
    sh->free = sh->free+(sh->len-len);
    sh->len = len;

    // 返回修剪后的 sds
    return s;
}

二进制安全

C语言的字符串只能用来保存ANSI字符,因为不能包含空字符。

所有的sds的api都会以处理二进制的方式来处理保存在sds字节数组的数据,不对这些数据进行任何的处理。

兼容部分c语言的字符串。

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

时间: 2024-10-11 05:44:23

Redis数据类型之字符串的相关文章

Redis数据类型之字符串String

String类型是Redis中最基本也最简单的一种数据类型 首先演示一些常用的命令 一.SET key value 和GET key SET key value 和 GET key  设置键值和获取值 SET将键today的值设为tuesday:GET取出键today的值 SET命令执行成功后返回OK:GET返回要取到的值 当一个key已经有值时,使用SET会覆盖其原有值,并且不受类型限制 today的原有值"tuesday"被"12"覆盖.Redis里没有整数类型

Redis 数据类型分析 字符串 哈希 列表 集合 有序集合 优缺点 分析 注意事项 存储结构

一.提高Redis使用性能秘诀 KEY尽量少的原则,能放在1个KEY的就放入1个KEY,KEY开销很大尽量减少与Redis发生的交互次数,能批量的就批量,能事务.管道的就事务.管道从业务架构分析确定使用哪种数据类型,从全局出发,如果类型选错了再改变就很不容易使用每一个Redis命令注意是O(1),还是O(N),切记滥用,认准每个命令的特性再使用也不迟使用PHP Redis的C语言扩展,性能远远高于PHP脚本编写的文件时刻清醒你往Redis里存储了什么,频繁交互.相对静态的小数据存储至Redis是

Redis数据类型之-- 字符串(string)

1.  String 类型 介绍:String是最简单的类型,你可以理解成与Memcached是一模一样的类型,一个Key对应一个Value. 可以完全实现Memcached的功能,而且效率要比Memcached高很多,同时可以设置Redis的定时数据持久化, 操作日志的记录以及主从复制等功能. 方法: 1. set     设置Key对应的值为string类型的value      如: set name  test001 2. setnx  设置key 对应的值为string类型的value

redis数据类型

Redis 数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). String(字符串) string是redis最基本的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据.比如jpg图片或者序列化的对象 . string类型是Redis最基本的数据类型,一个键最大能存储512MB. 实例: 在以上实例中我们使用了 Redis

redis数据类型简介1

数据类型 Strings 字符串是redis最基础类型数据.redis字符串是二进制安全的,这意味着一个redis字符串可以包含任意类型的数据,例如JPEG图像或者一个序列化的Ruby对象. 一个字符串最大可以达到512M. 你可以使用redis字符串做很多有趣的事情,例如:(1)可以用作原子计数器.配合使用INCR命令中的:INCR,DECR,INCRBY(2)使用APPEND命令扩展一个字符串(3)使用GETRANGE和SETRANGE命令,随机访问子字符串(4)使用GETBIT和SETBI

Redis数据类型简介

Redis 数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合). String(字符串) string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据.比如jpg图片或者序列化的对象 . string类型是Redis最基本的数据类型,一个键最大能存储512M

redis数据类型及使用场景

Redis数据类型  String: Strings 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字. 常用命令:  set,get,decr,incr,mget 等. 应用场景:String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类.即可以完全实现目前 Memcached 的功能,并且效率更高.还可以享受Redis的定时持久化,操作日志及 Replication等功能.除了提供与 Memcached 一样的get.set.in

Redis学习笔记---字符串类型

补充 上篇笔记博客中有些有些关键点未提到,现在这里补充下 redis help 命令 help命令应该是我们使用任何一款软件产品经常用到的命令,有时候通过help命令能够更快的获取相关帮助,而不仅仅通过百度.同样,在Redis中的help命名写的就非常简洁易懂,虽然是只有英文版的帮助信息,但是只要有一定应用基础的人都可以看懂,如: 127.0.0.1:6379> help redis-cli 3.0.2 Type: "help @<group>" to get a l

Redis系列--3、Redis数据类型

Redis支持5种数据类型,它们描述如下: Strings - 字符串 Redis的字符串是字节序列.在Redis中字符串是二进制安全的,这意味着他们有一个已知的长度,是没有任何特殊字符终止决定的,所以可以存储任何东西,最大长度可达512兆. 例子 redis 127.0.0.1:6379> SET name "yiibai" OK redis 127.0.0.1:6379> GET name "yiibai" 在上面的例子使用Redis命令set和ge