允拓冷水机,圣元股票,重庆南极圈信息网
本次学习除了基本内容之外主要思考三个问题:why(为什么)、what(原理是什么)、which(同类中还有哪些类似的东西,相比有什么区别)。
由于我对 java 比较熟悉,并且 java 中也有字符串和链表。所以本篇暂拿 redis 中的字符串和链表与 java 进行对比。
先看几个问题:
由于 c 语言的字符数组有着以上的局限性,所以 redis 和 java 都重新定义了自己的字符串结构。
redis 中的字符串是自己构建了一种叫做简单动态字符串(sds)的抽象类型标识的。它的具体结构如下:
struct sdshdr { //字符串长度 int len; // buf中未使用的字节数 int free; // 字节数组,用于保存字符串 char buf[]; }
redis 的这个数据结构,很好的解决了 c 语言字符数组的第1、2、3、4点局限性。而且值得注意的是 sdshdr 中的 buf 数组,也是以“\0”结尾的,所以buf的总长度为:len + free + 1。那么为什么要浪费这一个字节呢?主要是想重用 c 语言对于字符串的一些函数,比如连接、输出等等。
这里有一个点需要注意一下,就是 redis 不会对存储的字符串进行编码,存储和获取都是直接通过二进制进行传输的,所以理论上来说只要客户端的编码和解码方式一样,是不会出现乱码的。这也是上面 buf 的注释里写字节数组的原因。
java 的字符串呢?则是直接把字符串搞成了一个常量。如下:
public final class string implements java.io.serializable, comparable<string>, charsequence { /** the value is used for character storage. */ private final char value[]; /** cache the hash code for the string */ private int hash; // default to 0 ...... }
java 的字符串也解决了c语言字符数组的第 1/2/3/4 点。
现在我们再回去看一下 redis 中字符串的结构,有一个数组,有数组中存储数据的长度。想到了什么?java中 stringbuilder、stringbuffer、arraylist 是不是都是这个结构?他们的共同点呢?是不是都是可变的数组( stringbuilder、stringbuffer 可以看成可变的字符数组)?
造成这些差异的原因,主要就是其定位不一样。redis 的定位是缓存、要求快。java 的定位是语言,最重要的是跨平台及扩展性。
也同样看三个问题:
链表的产生主要是因为数组的局限性。
比如:插入、删除慢。不能动态增加元素。
redis 的链表结构如下:
typedef struct listnode { struct listnode *prev; //前驱节点,如果是list的头结点,则prev指向null struct listnode *next;//后继节点,如果是list尾部结点,则next指向null void *value; //万能指针,能够存放任何信息 } listnode; typedef struct list { listnode *head; //链表头结点指针 listnode *tail; //链表尾结点指针 //下面的三个函数指针就像类中的成员函数一样 void *(*dup)(void *ptr); //复制链表节点保存的值 void (*free)(void *ptr); //释放链表节点保存的值 int (*match)(void *ptr, void *key); //比较链表节点所保存的节点值和另一个输入的值是否相等 unsigned long len; //链表长度计数器 } list;
java 的链表结构如下:
public class linkedlist<e> extends abstractsequentiallist<e> implements list<e>, deque<e>, cloneable, java.io.serializable{ transient int size = 0; /** * pointer to first node. * invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */ transient node<e> first; /** * pointer to last node. * invariant: (first == null && last == null) || * (last.next == null && last.item != null) */ transient node<e> last; ....... }
基本一致,都是双向不循环链表。
双向的优点就是可以向前遍历,也可以向后遍历。缺点就是每个节点都需要浪费一个指针去指向前一个节点。
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
理解Redis持久化,RDB持久化和AOF持久化的不同处理方式
Redis 两类持久化方式,快照和全量追加日志的不同处理方式
网友评论