Redis数据结构之list列表

ops/2024/9/24 22:14:29/

一.list列表

列表相当于数组或者顺序表

它里面的元素是有序的,也就是可以通过下标进行访问。这里的有序的含义是要根据上下文区分的,有的时候,有序指的是升序/降序,有的时候有序指的是顺序很关键,俩个元素交换后就不是同一个集合了。这里的list就是第二种,对应的下标有对应的值。

所以说,同样的一个词,怎么解释要看上下文。就好比栈/堆,是数据结构?还是操作系统的?还是JVM的?

也比如同步,是同步互斥的同步?还是同步异步的同步?

这里的list并不是一个简单的数组,它的底层接近于双端队列deque:

如上图,这个list支持头尾高效的删除插入元素,所以可以将list当成一个栈/队列来使用。

redis有一个典型的应用场景,就是作为消息队列,最早的时候就是通过list类型,只不过后来redis又提供了stream类型

list列表中的元素是允许重复的,但是像hash这样的类型,field是不能够重复的(因为它获取value就是根据field,如果重复了就不知道获取哪个value了;而list就是根据下标进行访问)。

二.相关命令

1.lpush

一次可以插入一个或多个元素,而且是按照顺序依次进行头插,所以全部插入完毕后,最后写下的匀速就是在list的最前边

时间复杂度:O(1)

返回值:list的长度

如果key已经存在,而且对应的value类型不是list,就会报错

2.lrange查看对应的list中指定范围的元素

lrange key start stop  注意,这里的区间是左右都闭

下标支持负数

如果给定的区间非法,比如超出了范围,他就会尽可能地获取到对应的内容如下:

这体现了程序的容错能力,也体现了鲁棒性(你对我越粗鲁,我就表现得越棒)

3.lpushx

与lpush不同的是,当指定的list存在时(也就是key存在),才能将元素放进去,如果list不存在,就直接返回

list2先前没有创建,所以push不进去

4.rpush

其实lpush是left push,所以rpush就是right push,也就是尾插啦

5.lpop rpop

左删和右删

返回值是删除的元素

时间复杂度都是o(1)

小结一下,redis中的list是一个双端队列,俩头插入/删除的时间复杂度都是O(1),搭配使用rpush和lpop就相当于队列(尾进头出),搭配使用rpush和rpop就相当于栈(尾进尾出)。

6.lindex

lindex key index 给定下标,获取对应的元素

时间复杂度是O(N),其实这里的N指的是list中的元素个数,当元素很少时,就能看做O(1)

下标非法就返回nil

7.linsert

linsert key before/after pivot element  在指定元素pivot之前/后插入元素element

返回值是插入之后的list的长度

8.llen

返回list的长度

时间复杂度:O(1)

9.lrem

lrem key count element 指定删除对应的key中的count个element,如果不够count个,那就能删几个删几个

count>0 那就从head开始删

count<0那就从tail开始删

count=0那就删除所有的element

10.ltrim

ltrim key start stop 保留start到stop之间的元素

11.lset

lset key index element 根据下标,修改元素

lindex对于下标的越界访问能够很好的处理,直接返回nil,但是对于lset来说,则会报错

时间复杂度:O(1)

12.阻塞版本

首先讲一下什么是阻塞:就是当前的线程不走了,代码不继续执行了,会在满足一定的条件之后被唤醒。

阻塞版本的头尾删除是:blpop brpop

当list不为空时,blpop和brpop就和lpop rpop效果完全一样;但当为空时,b版本的就会阻塞,直到再次插入元素。

咱们讲过阻塞队列(BlockingQueue)。多线程的时候,讲过一个生产者消费者模型,就是使用队列作为交易场所,期望这个队列右两个特性:1.线程安全2.阻塞->如果队列为空,尝试出队列就产生阻塞,如果队列为满,尝试入队列,就产生阻塞,直到队列不满解除阻塞。

redis中的list也相当于阻塞队列一样。线程安全是通过单线程模型支持的,阻塞则只支持队列为空的条件,不支持队列为满。

阻塞版本会根据timeout阻塞一段时间,但是阻塞期间可以执行其他指令。可以显示设置阻塞时间,超过后就自动返回。

blpop key [key……] timeout

先看指定一个key的版本,打开两个客户端

第一个窗口中先执行blpop,设定时间为100秒

然后第二个窗口里个该list设值

在回到第一个窗口,发现blpop出现了结果,返回值是list的名称加删除的结果加使用的时间

如果针对多个list进行操作,那么他也会尝试获取,但要是都没有元素,那就是最先插入元素的客户端会得到弹出的元素,但如果都有元素,那就是返回最先执行的客户端中的元素

先看都为空的情况:

再看都为满的情况:

如上,最先执行blpop的是lt2,所以返回lt2的

这俩个阻塞命令的用途主要就是作为消息队列,可以一定程度慢则消息队列这样的要求,但是整体来说还是有局限的

三.内部编码

列表的内部编码有两种:

1.ziplist压缩列表,当列表的元素个数小于list-ziplist-entries的配置时(默认是512个)同时列表中每一个元素的长度都小于list-max-ziplist-value的设置是,就会选用ziplist的内部编码方式来减少内存消耗

2.linkedlist,除上述之外都是linkedlist

但现在已经不适用这种方式了,而是直接使用quicklist,quicklist相当于是列表和压缩列表的结合体,就是每一个压缩列表都不要太大,同时再把多个压缩列表用链式结构连起来

四.list应用场景

1.list作为数组

list作为数组存储多个元素

在MySQL中,如下表示学生和班级的信息

如果使用redis,就可以像下面一样:

也就是每一个学生/班级对应一个list,每一个list存放的都是学生信息/班级信息。

2.redis作为消息队列

一个列表,多人获取:

谁先执行brpop这个命令,谁就先拿到新来的元素。

像这样的设定就能够达到“轮询式”的效果:假设消费者执行的顺序是1,2,3,当新元素到达后,消费者1就先拿到元素并且退出,如果消费者1还想再钠元素,就要重新执行brpop命令;此时再来一个新元素就是消费者2拿到元素,它想再拿到元素就得重新执行brpop命令;再来一个新元素就是消费者3拿到了~~,就好像食堂排队打饭一样

多个列表,多人获取:

多个列表/频道,这种场景非常常见,就比如抖音/快手~~

有一个通道是传输视频数据,还有一个通道传输弹幕,还有一个频道传输点赞、转发、收藏数据,还有一个频道传输评论数据

搞成多个频道,就可以在某种数据发生问题时,不会对其他频道的数据产生影响(解耦合)

就比如上图中,brpop key1 key2的key1阻塞了,但是对key2不会有影响,还能够拿到数据,堆key3也不会有影响,最大限度地减少了阻塞带来的风险

3.微博timeline

每一个用户都有属于自己的timeline(微博列表),现在需要分页展示文章列表,就可以使用到list。因为list不单是有许多,同时支持按照索引范围获取元素

首先,每一篇微博使用hash结构存储(一篇微博对应一个hash,一个field对应一个value)

其次,要向用户添加微博,user:<uid>:mblogs就是微博的键

最后,分页获取用户的timeline

但是当前一页中要显示多少数据,不确定,就可能会到这上面的循环次数比较多,从而会触发很多次hgetall,也就是很多次网络请求。此时可以考虑使用pipeline(流水线)模式批量提交用户命令,或者微博不采用hash进行存储,而是用字符串形式,然后用mget来获取(但一般不这样)

pipeline:流水线/管道,多个redis命令合并为一个网络请求进行通信,大大降低了客户端和服务器之间的交互次数


http://www.ppmy.cn/ops/115488.html

相关文章

6-1 jmu-Java-04面向对象进阶-01-接口-匿名内部类ActionListener

分数 10 全屏浏览 切换布局 作者 郑如滨 单位 集美大学 已有MyStarter类(你无需编写&#xff0c;直接使用)&#xff0c;其具有&#xff1a;构造函数&#xff1a;public MyStarter(ActionListener ac)方法&#xff1a;start()启动任务 ###main方法执行流程&#xff1a; 输…

Qt开发技巧(四)“tr“使用,时间类使用,Qt容器取值,类对象的删除,QPainter画家类,QString的转换,用好 QVariant类型

继续讲一些Qt技巧操作 1.非必要不用"tr" 如果程序运行场景确定是某一固定语言&#xff0c;就不需要用tr,"tr"之主要针对多语种翻译的&#xff0c;因为tr的本意是包含英文&#xff0c;然后翻译到其他语言比如中文&#xff0c;不要滥用tr&#xff0c;如果没有…

el-upload如何自定展示上传的文件

Element UI 中&#xff0c;el-upload 组件支持通过插槽&#xff08;slot&#xff09;来自定义文件列表的展示方式。这通常是通过 file-list 插槽来实现的。下面是一个使用 el-upload 组件并通过 file-list 插槽来自定义文件列表展示的完整示例代码。 在这个示例中&#xff0c;…

2017年国赛高教杯数学建模C题颜色与物质浓度辨识解题全过程文档及程序

2017年国赛高教杯数学建模 C题 颜色与物质浓度辨识 比色法是目前常用的一种检测物质浓度的方法&#xff0c;即把待测物质制备成溶液后滴在特定的白色试纸表面&#xff0c;等其充分反应以后获得一张有颜色的试纸&#xff0c;再把该颜色试纸与一个标准比色卡进行对比&#xff0c…

牛客小白月赛101(A~E)

文章目录 写在前面A tb的区间问题思路code B tb的字符串问题思路code C tb的路径问题思路code D tb的平方问题思路code E tb的数数问题思路code 牛客小白月赛101 写在前面 最近几天没怎么刷题&#xff0c;昨天晚上打的这场牛客月赛打的很烂&#xff0c;隔几天不刷题感觉自己的…

把设计模式用起来!(4) 用不好模式?之原理不明

&#xff08;清华大学出版社 《把设计模式用起来》书稿试读&#xff09; 上一篇&#xff1a;把设计模式用起来&#xff01;&#xff08;3&#xff09;用不好模式&#xff1f;之时机不对 为什么用不好设计模式&#xff1f;——原理不明 难搞的顾客&#xff1a;“抹这种霜&#…

Elasticsearch:检索增强生成背后的重要思想

作者&#xff1a;来自 Elastic Jessica L. Moszkowicz 星期天晚上 10 点&#xff0c;我九年级的女儿哭着冲进我的房间。她说她对代数一无所知&#xff0c;注定要失败。我进入超级妈妈模式&#xff0c;却发现我一点高中数学知识都不记得了。于是&#xff0c;我做了任何一位超级妈…

第十四届蓝桥杯嵌入式国赛

一. 前言 本篇博客主要讲述十四届蓝桥杯嵌入式的国赛题目&#xff0c;包括STM32CubeMx的相关配置以及相关功能实现代码以及我在做题过程中所遇到的一些问题和总结收获。如果有兴趣的伙伴还可以去做做其它届的真题&#xff0c;可去 蓝桥云课 上搜索历届真题即可。 二. 题目概述 …