Redis数据结构之list列表

news2024/11/15 18:06:16

一.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.coloradmin.cn/o/2157177.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring6梳理10—— 依赖注入之注入数组类型属性

以上笔记来源&#xff1a; 尚硅谷Spring零基础入门到进阶&#xff0c;一套搞定spring6全套视频教程&#xff08;源码级讲解&#xff09;https://www.bilibili.com/video/BV1kR4y1b7Qc 目录 10 依赖注入之注入数组类型属性 10.1 创建Emp实体类&#xff0c;Dept实体类 10.2…

Java 每日一刊(第15期):内部类

文章目录 前言内部类成员内部类&#xff08;Member Inner Class&#xff09;静态内部类&#xff08;Static Nested Class&#xff09;局部内部类&#xff08;Local Inner Class&#xff09;匿名内部类&#xff08;Anonymous Inner Class&#xff09; 内部类的详细对比内部类字节…

浅谈Spring Cloud:Nacos的配置

Nacos&#xff0c;一个更易于构建云原生应用的动态服务发现&#xff0c;配置管理和服务管理平台。所以Nacos是⼀个注册中心组件&#xff0c;但它又不仅仅是注册中心组件。 目录 安装 注册 负载均衡 环境隔离 配置管理 搭建集群 安装 在官网下载好安装包解压后&#xf…

深度学习01-概述

深度学习是机器学习的一个子集。机器学习是实现人工智能的一种途径&#xff0c;而深度学习则是通过多层神经网络模拟人类大脑的方式进行学习和知识提取。 深度学习的关键特点&#xff1a; 1. 自动提取特征&#xff1a;与传统的机器学习方法不同&#xff0c;深度学习不需要手动…

手机在网状态查询接口如何用Java进行调用?

一、什么是手机在网状态查询接口&#xff1f; 手机在网状态查询接口&#xff0c;又叫运营商在网状态查询&#xff0c;手机号在网状态查询&#xff0c;传入手机号码&#xff0c;查询该手机号的在网状态&#xff0c;返回内容有正常使用、停机、在网但不可用、不在网&#xff08;…

【网络】高级IO——epoll版本TCP服务器初阶

目录 前言 一&#xff0c;epoll的三个系统调用接口 1.1.epoll_create函数 1.1.1.epoll_create函数干了什么 1.2. epoll_ctl函数 1.2.1.epoll_ctl函数函数干了什么 1.3.epoll_wait函数 1.3.1.epoll_wait到底干了什么 1.4.epoll的工作过程中内核在干什么 二&#xff0c;…

【Elasticsearch系列廿】Logstash 学习

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

PostgreSQL 的log_hostname 参数测试

PostgreSQL 的log_hostname 参数测试 log_hostname 是 PostgreSQL 配置文件 (postgresql.conf) 中的一个参数&#xff0c;用于控制是否在日志条目中记录客户端主机名。默认情况下&#xff0c;PostgreSQL 只记录客户端的IP地址&#xff0c;而 log_hostname 参数允许数据库管理员…

【最基础最直观的排序 —— 冒泡排序算法】

最基础最直观的排序 —— 冒泡排序算法 冒泡排序&#xff08;Bubble Sort&#xff09;是一种计算机科学领域的较简单的排序算法&#xff0c;属于交换排序。其基本思想是在待排序的一组数中&#xff0c;将相邻的两个数进行比较&#xff0c;若前面的数比后面的数大就交换两数&am…

农产品商城系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;产品分类管理&#xff0c;热销农产品管理&#xff0c;订单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;热销弄产品&#xff0c;网站公告&#…

基于c++实现的简易shell

代码逻辑 核心思想 解析命令行&#xff0c;拆解命令及其选项创建子进程&#xff0c;在子进程中执行命令如果是前台执行命令&#xff0c;则父进程就阻塞等待子进程中命令执行结束后回收子进程的资源如果是后台执行命令&#xff0c;则父进程不进行阻塞等待&#xff0c;可继续向下…

STM32 软件触发ADC采集

0.91寸OLED屏幕大小的音频频谱&#xff0c;炫酷&#xff01; STM32另一个很少人知道的的功能——时钟监测 晶振与软件的关系&#xff08;深度理解&#xff09; STM32单片机一种另类的IO初始化方法 ADC是一个十分重要的功能&#xff0c;几乎任何一款单片机都会包含这个功能&a…

记一次MySQL索引不当引发死锁问题

一、前言 在并发量很低的情况下&#xff0c;mysql 的响应时延一切正常&#xff0c;一旦并发量上去了&#xff0c;mysql就会出现死锁的情况&#xff0c;你有没有遇到过&#xff1f;到底是是什么原因导致的呢&#xff0c;让我们一起看看真实的案例。 二、遇到的问题 先介绍一下…

LabVIEW提高开发效率技巧----利用第三方库和工具

LabVIEW开发不仅依赖于自身强大的图形化编程能力&#xff0c;还得益于其庞大的用户社区和丰富的第三方库。这些工具和库能够帮助开发者快速解决问题&#xff0c;提升开发效率&#xff0c;避免从头开始编写代码。 1. LabVIEW工具网络&#xff08;NI Tools Network&#xff09; …

MateBook 16s 2023在Deepin下开启性能模式,调节风扇转速到最大,全网首发!

方法 在Deepin下按住Fnp快捷键&#xff0c;开启性能模式。 验证 首先去debian下载acpi-call-dkms https://packages.debian.org/sid/all/acpi-call-dkms/download 然后使用root用户执行&#xff1a; apt install --simulate ./acpi-call-dkms_1.2.2-2.1_all.deb apt inst…

LeetCode 面试经典150题 191.位1的个数

Java中的算术右移和逻辑右移的区别 题目&#xff1a;编写一个函数&#xff0c;获取一个正整数的二进制形式并返回其二进制表达式中设置位的个数&#xff08;也被称为汉明重量&#xff09;。 设置位的个数即二进制中1的个数。 思路&#xff1a;方法一&#xff1a;因为正数的原…

基于阿里云免费部署Qwen1-8B-chat模型并进行lora参数微调从0到1上手操作

文章目录 一、申请资源二、创建实例三、克隆微调数据四、部署Qwen1-8B-chat模型1、环境配置2、模型下载3、本地模型部署 五、模型微调1、拉取Qwen仓库源码2、微调配置3、合并微调参数4、本地部署微调模型 一、申请资源 阿里云账号申请PAI资源详细教程我已于部署ChatGLM3时写过…

Golang | Leetcode Golang题解之第430题扁平化多级双向链表

题目&#xff1a; 题解&#xff1a; func dfs(node *Node) (last *Node) {cur : nodefor cur ! nil {next : cur.Next// 如果有子节点&#xff0c;那么首先处理子节点if cur.Child ! nil {childLast : dfs(cur.Child)next cur.Next// 将 node 与 child 相连cur.Next cur.Chi…

遗传算法与深度学习实战(14)——进化策略详解与实现

遗传算法与深度学习实战&#xff08;14&#xff09;——进化策略详解与实现 0. 前言1. 进化策略1.1 进化策略原理1.2 将进化策略应用于函数逼近 2. 实现进化策略小结系列链接 0. 前言 进化策略 (Evolutionary Strategies, ES) 是进化计算和遗传方法的扩展&#xff0c;增加了控…

【Python学习手册(第四版)】学习笔记24-高级模块话题

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本来计划中秋发布几篇文章&#xff0c;结果阳了&#xff0c;发烧、头疼、咽疼&#xff0c;修养了近一周&#xff0c;还没好完。希望大家都能有个好身体&#xff0…