Redis的列表相当于java中的LinkedList,它是一个链表,也就是说list的插入和删除操作非常快,但是索引定位会比较慢。
当列表中最后一个元素被弹出后,该数据结构会被自动删除,内存被回收。
list内部是一个双向链表,每个元素都使用双向指针顺序,串起来可以同时支持前向,后向遍历。
结构示意图:
命令 | 描述 |
BLPOP key timeout | 移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 |
BRPOP key timeout | 移出并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 |
LINDEX key index | 通过索引获取列表中的元素 |
LLEN | 获取列表长度 |
LPOP key | 移出并获取列表的第一个元素 |
LPUSH key value1 [value2 ...] | 将一个或者多个值插入到列表的头部 |
LPUSHX key value | 将一个值插入到已存在的列表头部,如果列表不存在,则返回0 |
LRANGE key start end | 获取列表指定范围内的元素 |
LSET key index value | 通过索引设置列表元素的值 |
LTRIM key start end | 对一个列表进行删减,只保留指定范围内的元素,不在范围内的元素将被删除 |
RPOP key | 移出列表中的最后一个元素 |
RPUSH key value1 [value2 ...] | 将一个或多个元素插入到列表的尾部 |
RPUSHX key value | 将一个值插入到已存在的列表尾部,如果列表不存在,则返回0 |
LREM key count value | 根据count值,移出列表中与参数value相等的元素。count > 0: 从表头开始向表尾搜索,移出与value相等的值,数量为count; count < 0:从表尾开始向表头搜索,移出与value相等的值吗,数量为count的绝对值;count = 0:移出表中所有与value相等的值 |
队列是先进先出的数据结构,可用于消息排队和异步处理的操作,它会确保元素的访问顺序。
操作:RPUSH将元素插入到列表中的最后一个元素,然后LPOP获取列表的第一个元素
栈是先进后出的数据结构,和队列正好相反,它会确保最后一个存储的会第一个出现。
操作:RPUSH将元素插入到列表中的最后一个元素,然后RPOP获取列表的最后一个元素
由于Redis的列表相当于Java的linkedlist,因此它的一些方法需要对链表进行遍历,因此在使用的时候需要特别进行注意。
lindex相当于Java链表的get(index)方法,它需要对链表进行遍历,性能随着参数index的增大而变差,因此在使用的时候要慎用,时间复杂度为o(n)。
获取0到-1范围内的元素,即获取所有的元素,因此需要慎用,时间复杂度为o(n)。
保留从1到-1区间内的元素,区间之外的统统砍掉。但-1表示倒数第一个,该操作即保留所有的元素,因此需要慎用,时间复杂度为o(n)
由于普通的列表需要一个向前指针prev和一个向后的指针next,这2个指针就要占用16个字节(64位操作系统的指针占8个字节),这样链表的附加空间相对太高;并且链表中每个节点的内存都是单独分配的,会加剧内存的碎片化,影响内存管理效率。
因此将linkedlist按段切分,每一段使用压缩列表ziplist让存储紧凑,并且根据压缩深度对ziplist进行压缩存储,然后多个ziplist之间再使用双向指针串接起来,从而组成了我们需要的quicklist快速列表。
压缩列表是一块连续的内存空间,元素之间紧挨着存储,没有任何冗余空隙。调试看下:
127.0.0.1:6379> lpush list k1 k2 k3 (integer) 3 127.0.0.1:6379> LLEN list (integer) 3 127.0.0.1:6379> debug object list Value at:00007FCD53D1D570 refcount:1 encoding:ziplist serializedlength:24 lru:15778389 lru_seconds_idle:5 127.0.0.1:6379>
我们可以看到输出的encoding为ziplist,这就表示内部采用的是压缩列表结构进行存储。
原文:https://www.cnblogs.com/springhub/p/13172669.html