Redis字符串的巧妙处理
2015-08-11 17:56
435 查看
sds在Redis中是实现字符串对象的工具,并且完全取代char*.
char*的功能比较单一,不能实现Redis对字符串高效处理的需求,char*的性能瓶颈主要在:计算字符串长度需要使用strlen函数,该函数的时间复杂度是O(N),而在Redis中计算字符串长度的操作十分频繁,O(N)的时间复杂度完全不能接受,sds实现能在O(1)时间内得到字符串的长度值;同时,在处理字符串追加append操作时,如果使用char*则需要多次重新分配内存操作。
通过增加len字段,就可以实现在O(1)时间复杂度内得到字符串的长度,增加free字段,在需要append字符串时,如果free的值大于等于需要append的字符串长度,那么直接追加即可,不需要重新分配内存。sizeof(sdshdr) = 8.
redis巧妙的使用柔性数组技巧,减少结构体占用内存,并可以快速返回字符串长度,弹性增加大小,压缩占用内存空。
建议参考sds.c源文件实现
实例代码:
参考地址:http://redisbook.readthedocs.org/en/latest/internal-datastruct/sds.html
char*的功能比较单一,不能实现Redis对字符串高效处理的需求,char*的性能瓶颈主要在:计算字符串长度需要使用strlen函数,该函数的时间复杂度是O(N),而在Redis中计算字符串长度的操作十分频繁,O(N)的时间复杂度完全不能接受,sds实现能在O(1)时间内得到字符串的长度值;同时,在处理字符串追加append操作时,如果使用char*则需要多次重新分配内存操作。
通过增加len字段,就可以实现在O(1)时间复杂度内得到字符串的长度,增加free字段,在需要append字符串时,如果free的值大于等于需要append的字符串长度,那么直接追加即可,不需要重新分配内存。sizeof(sdshdr) = 8.
redis巧妙的使用柔性数组技巧,减少结构体占用内存,并可以快速返回字符串长度,弹性增加大小,压缩占用内存空。
建议参考sds.c源文件实现
实例代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef char* sds; struct sdshdr{ unsigned int len; 字符串长度 unsigned int free; char buf[]; 字符串 }; sds sdsnewlen(const void *init, size_t initlen) { struct sdshdr *sh; if (init) { sh = malloc(sizeof(struct sdshdr)+initlen+1); } else { sh = malloc(sizeof(struct sdshdr)+initlen+1); } if (sh == NULL) return NULL; sh->len = initlen; sh->free = 0; if (initlen && init) memcpy(sh->buf, init, initlen); sh->buf[initlen] = '\0'; return (char*)sh->buf; 注意:这里返回的是字符串,很好的实现了隐藏结构体 } sds sdsnew(const char *init) { size_t initlen = (init == NULL) ? 0 : strlen(init); return sdsnewlen(init, initlen); } static inline size_t sdslen(const sds s) { struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr))); return sh->len; 这里直接获取到字符串长度,不用在计算长度 } int main(int argc, char *argv[]) { const char *str = "haha hehe lala"; sds a = sdsnew(str); int n = sdslen(a); printf("%d\n", n); printf("%d\n", strlen(str)); return 0; }redis利用指针巧妙的隐藏结构体,对外看来跟char*无异
简单动态字符串sds中函数API
函数名称 | 作用 | 复杂度 |
sdsnewlen | 创建一个指定长度的sds,接受一个指定的C字符串作为初始化值 | O(N) |
sdsempty | 创建一个只包含空字符串””的sds | O(N) |
sdsnew | 根据给定的C字符串,创建一个相应的sds | O(N) |
sdsdup | 复制给定的sds | O(N) |
sdsfree | 释放给定的sds | O(1) |
sdsupdatelen | 更新给定sds所对应的sdshdr的free与len值 | O(1) |
sdsclear | 清除给定sds的buf,将buf初始化为””,同时修改对应sdshdr的free与len值 | O(1) |
sdsMakeRoomFor | 对给定sds对应sdshdr的buf进行扩展 | O(N) |
sdsRemoveFreeSpace | 在不改动sds的前提下,将buf的多余空间释放 | O(N) |
sdsAllocSize | 计算给定的sds所占的内存大小 | O(1) |
sdsIncrLen | 对给定sds的buf的右端进行扩展或缩小 | O(1) |
sdsgrowzero | 将给定的sds扩展到指定的长度,空余的部分用\0进行填充 | O(N) |
sdscatlen | 将一个C字符串追加到给定的sds对应sdshdr的buf | O(N) |
sdscpylen | 将一个C字符串复制到sds中,需要依据sds的总长度来判断是否需要扩展 | O(N) |
sdscatprintf | 通过格式化输出形式,来追加到给定的sds | O(N) |
sdstrim | 对给定sds,删除前端/后端在给定的C字符串中的字符 | O(N) |
sdsrange | 截取给定sds,[start,end]字符串 | O(N) |
sdscmp | 比较两个sds的大小 | O(N) |
sdssplitlen | 对给定的字符串s按照给定的sep分隔字符串来进行切割 | O(N) |
相关文章推荐
- Redis使用误区
- 谈谈陌陌争霸在数据库方面踩过的坑( Redis 篇)
- redis主从配置及主从切换
- Redis主从复制
- Redis监控方案
- Node.js 中使用 Redis 来实现定时任务
- 用 redis 实现和保护 12306
- Redis lua 常用脚本记录
- redis使用jmeter测试
- 详解Redis中的双链表结构
- Redis安装及使用介绍
- 超强、超详细Redis数据库入门教程
- 多台redis部署及同步
- Redis2.8 单个redis JedisPool 与spring的集成配置
- Redis学习笔记
- 基于Twemproxy的Redis集群方案
- 超强、超详细Redis入门教程
- RedisTemplate SerializationFailedException: Failed to deserialize payload 异常解决
- 初学Redis(2)——用Redis作为Mysql数据库的缓存
- Microsoft Visual C++ 2010(86) Redistributable不能安装完美解决