`

Redis-3 数据类型详解之List

阅读更多

1. 理论篇

在学习List之前先对其来一点理论的了解是有好处的。

简单来说比如 10,20,1,2,3  的序列就是一个List。不过 List 是继承自ArrayList 还是LinkedList,他们之间的差别还是很大的。LinkedList 意味着即使你的 List 列表中有一百万个数据,在 List 的头或者 尾部插入数据的时间都是恒定的。比如无论数组里面有10个或者1000万个元素,使用LPUSH 把一个元素插入到 List 的头部或者尾部的时候,他们的时间是相等的。

 

那他的确定是什么呢?在使用下表访问 ArrayList 的元素的时候,它的速度很快,可以说是及时的;而在访问 LinkedList 的元素的额时候,速度就不那么快了,它与访问的元素的下标的数量是有关的。

 

Redis List 是继承自LinkedList 的,因为对于数据库来说能够在长列表的时候非常快的插入数据是非常关键的。另一个重要的因素是你即将要看到的:Redis 可以在常数时间内取得常数长度。

 

当访问一个大集合的中部元素是比较重要的时候,还有其他的数据结构可以使用--Sorted Set。我们后续的教程会讲 Sorted Set。

2. Redis List 入门

LPUSH 命令添加一个新元素到一个列表的左边(头部),然而RPUSH 命令添加一个新元素到一个列表的右边(尾部)。最后,LRANGE命令在列表中获取一个范围的元素。

 

Java代码 
  1. 127.0.0.1:6666> RPUSH mylist a  
  2. (integer) 1  
  3. 127.0.0.1:6666> rpush mylist b  
  4. (integer) 2  
  5. 127.0.0.1:6666> lpush mylist first  
  6. (integer) 3  
  7. 127.0.0.1:6666> lrange mylist 0 -1  
  8. 1"first"  
  9. 2"a"  
  10. 3"b"  

 注意LRANGE 有两个下表,范围内的第一个和最后一个元素都会返回。两个下标都可以是负值,这告诉 Redis 从末尾开始计数:所以 -1 是最后一个元素,-2 是倒数第二个元素等等。

 

正如你所见,RPUSH 添加元素到列表的右边,而LPUSH 添加元素到列表的左边。

这两个命令都是可变参数的命令,这意味着你可以很随意的添加多个元素到列表中。

 

Java代码 
  1. 127.0.0.1:6666> rpush mylist 1 2 3 4 5 "mylast"  
  2. (integer) 9  
  3. 127.0.0.1:6666> lrange mylist 0 -1  
  4. 1"first"  
  5. 2"a"  
  6. 3"b"  
  7. 4"1"  
  8. 5"2"  
  9. 6"3"  
  10. 7"4"  
  11. 8"5"  
  12. 9"mylast"  

 

Redis 列表上定义的一个重要的操作是弹出元素(pop elements)。弹出元素操作即使Redis 列表检索元素的操作,同时也是列表消除元素的操作。你可以从左边和右边弹出元素,与你从左边和右边添加元素是非常相似的:

Java代码 
  1. 127.0.0.1:6666> rpush mylist a b c  
  2. (integer) 3  
  3. 127.0.0.1:6666> rpop mylist  
  4. "c"  
  5. 127.0.0.1:6666> lpop mylist  
  6. "a"  
  7. 127.0.0.1:6666> lpop mylist  
  8. "b"  

 

我们往列表中添加了三个元素,也弹出了三个元素,那么列表现在则是空的。如果我们尝试再继续弹出元素,那么将获得如下结果:

Java代码 
  1. 127.0.0.1:6666> lpop mylist  
  2. (nil)  

 

如果列表中没有元素,Redis 则会返回一个 NULL 值。

 

 3. 列表的常见使用情形

列表对于多任务是非常又有用的,下面是两个非常有代表性的用法:

  • 记录用户提交到社交网络上的最新的更新
  • 进程间的通信,使用生产者-消费者模式,生产者把一个条目压进列表中,消费者消费这些条目并且执行动作。Redis 有特别的列表命令可以使这种情况更加可靠和高效。

 

 注:此部分官方文档有实例,可以看看

 

 4.有上限的列表

在很多场景中,我们仅仅使用List存储最新的条目,无论他们是下面的:社交网络更新、日志或者其他什么。

 

Redis 列表允许我们使用列表作为一个有上限的集合,它使用LTRIM仅存储最新的条目并且丢弃最旧的数据。

LTRIM 命令与LRANGE命令十分相似,它不展示指定的元素范围而是把这个范围设置为新的列表值。给定的范围之外的元素会被移除。

Java代码 
  1. 127.0.0.1:6666> rpush mylist 1 2 3 4 5  
  2. (integer) 5  
  3. 127.0.0.1:6666> ltrim mylist 0 2  
  4. OK  
  5. 127.0.0.1:6666> lrange mylist 0 -1  
  6. 1"1"  
  7. 2"2"  
  8. 3"3"  

 

下面的 LTRIM 命令告诉Redis仅仅保留从下标0到2的元素,其他的都被丢弃。这就允许一个非常简单的但是有用的模式:对一个列表进行压入操作 +列表调整操作组合,这为了实现添加一个新的元素并且丢弃掉超出限制的元素:

Java代码 
  1. LPUSH mylist <some element>  
  2. LTRIM mylist 0 999  

 

 上面的组合添加一个新的元素,并且仅仅把最新的1000个元素保存入列表中。使用LRANGE你可以访问最顶部的元素而且不需要记住特定的老数据。

注:虽然LRANGE从技术上讲是个O(N) 命令,但是访问列表头部或者尾部的小范围是个及时的操作。

 

5. 列表的阻塞操作

 列表有一个特别的特性使其适合实现队列,并且通常作为一个内部进程通信系统的构建基块:阻塞操作。

 

比如你想要使用一个进程把条目压入列表,并且使用一个不同的进程来实际上对这些条目做一些工作。这是普通的生产者/消费者模式,并且可以使用下面的方式来实现:

  • 要把条目压入列表,生产者调用LPUSH
  • 要从列表中提取或者处理条目,消费者调用RPOP

然而,很有可能有时列表是空的并且没有什么可处理的,所以RPOP仅仅返回NULL。在这种情况下,消费者别强制等待一些时间并且使用RPOP重试。这被称作轮询(polling),并且在这种情形下他不是一个好的做法,因为它有如下缺点:

  1. 强制Redis和客户端运行无用的命令(当列表为空的时候,所有的请求都在做无用功,他们仅仅返回NULL)
  2. 在消费者NULL的时候,为条目的处理添加一个延迟,它等待一段时间。为了使延迟更小,we could wait less between calls to RPOP, with the effect of amplifying problem number 1, i.e. more useless calls to Redis.

所以,Redis实现了BRPOP 和 BLPOP 命令,他们是当列表为空时可以阻塞版本的 RPOP 和 LPOP :他们仅仅当一个新的元素被添加进入列表的时候或者当用户指定的过期时间到达的时候才返回给调用者。

 

下面是我们可以在工作者中(worker)调用BRPOP的例子:

 

Java代码 
  1. 127.0.0.1:6666> brpop tasks 10  
  2. 1"tasks"  
  3. 2"12"  

 

 

这个效果是我在执行完上述的命令之后,程序阻塞了;然后在另一个客户端执行了 RPUSH tasks 12 命令,这时候阻塞的程序就会继续执行,因为它检测到了有新的元素的进入。

 

 brpop tasks 10 的含义是:等待 tasks 列表中的元素,但是如果在 5 秒以后还没有元素可以获取到的话就返回程序。

 

注意:你可以使用 0 作为过期时间以一直等待元素,并且你也可以指定多个而不止一个列表,这样可以同时等待多个列表,并且当第一个列表收到元素时收到通知。

 

关于BRPOP的几个值得注意的地方:

1. 客户端以一种有序的方式接受服务:当一个元素被其他客户端压入到列表中或者其他情况,一个列表阻塞等待的第一个客户端将会接收到服务。

2. 返回值与RPOP相比是不一样的:由于它也包含着键的名字,所以它是两个元素的数组,这是因为BRPOP 和 BLPOP 能够等待来自多个列表的元素。

3. 如果已经到了过期时间,那么将返回NULL。

 

关于列表和他的阻塞选项,你还有很多需要了解的。关于下述的内容建议你读更多资料:

  • 可以使用RPOPLPUSH来构建安全的队列或者循环队列
  • BRPOPLPUSH 是命令的命令的阻塞备选方案

额。。。下面依然是我建的一个公众帐号,可以关注一下哦,谢谢

 

1
2
分享到:
评论

相关推荐

    redis命令集合,redis命令详解

    TYPE key 返回某个key元素的数据类型 ( none:不存在,string:字符,list,set,zset,hash) KEYS pattern 返回匹配的key列表 (KEYS foo*:查找foo开头的keys) RANDOMKEY 随机获得一个已经存在的key,如果当前数据库为空,...

    Redis 数据类型的详解

    Redis 数据类型的详解 概要: Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。 String(字符串) string是redis最基本的类型,你可以理解成与...

    Redis新手入门详解

    redis是一个开源的key-value数据库。它又经常被认为是一个数据结构服务器。因为它的value不仅包括基本的string类型还有list,set ,sorted set和hash类型。当然这些类型的元素也都是string类型。也就是说list,set这些...

    详解Redis中的List类型

    本系列将和大家分享Redis分布式缓存,本章主要简单介绍下Redis中的List类型,以及如何使用Redis解决博客数据分页、生产者消费者模型和发布订阅等问题。 Redis List的实现为一个双向链表,即可以支持反向查找和遍历,...

    详解Redis 数据类型

    Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。 String(字符串) string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,...

    Redis安装配置详解.pdf

    它通常被称为数据结构服务器,因为值(value)可以是 字符串(string)、哈希(Hash)、列表(list)、集合(sets)、有序集合(sorted sets)等类型。它被广泛用于缓存、消息代理、分布式锁等领域,是分布式架构中不可或缺的...

    Redis总结.xmind

    REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key...它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

    redis基本类型和使用方法详解

    redis存储数据的基本类型有:string(字符串类型)、hash(散列类型)、list(列表类型)、set(集合类型)、zset(有序集合类型)。 依次做一些练习。redis命令不区分大小写。 key相关操作 127.0.0.1:6379&gt; set ...

    Redis实战,详细讲解redis的使用方式

    这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是...

    Redis缓存数据库详解

    Redis最为常用的数据类型主要有以下五种:1)String2)Hash3)List4)Set5)Sortedset在具体描述这几种数据类型之前,我们先通过一张图了解下Redis内部内存管理中是如何描述这些不同数据类型的:首先Redis内部使用一...

    laravel使用Redis实现网站缓存读取的方法详解

    redis的简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。 Redis 与其他 key – value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保持在磁盘... 丰富的数据类型

    MySQL和Redis实现二级缓存的方法详解

    redis简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库 Redis 与其他 key – value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保存... 丰富的数据类型 – Redis

    详解redis端口号

    它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。 Redis 查看端口使用情况 1,首先查询该端口的 pid,使用命令 【ne

    详解Redis中的双链表结构

    Redis中双链表实现的基本结构: 1.节点结构 typedef struct listNode { struct listNode *prev; //前向节点 struct listNode *next; //后向节点 void *value; //该节点的值 } listNode; 2.双向链表结构 ...

    Python安装并操作redis实现流程详解

    这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是...

    利用yum安装Redis的方法详解

    这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是...

    详解c# 类型转换

    类型转换从根本上说是类型铸造,或者说是把数据从一种类型转换为另一种类型。在 C# 中,类型铸造有两种形式: 隐式类型转换 – 这些转换是 C# 默认的以安全方式进行的转换, 不会导致数据丢失。例如,从小的整数类型...

    图文详解Windows下使用Redis缓存工具的方法

    这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是...

    Golang中Set类型的实现方法示例详解

    对于Set类型的数据结构,其实本质上跟List没什么多大的区别。无非是Set不能含有重复的Item的特性,Set有初始化、Add、Clear、Remove、Contains等操作。接下来看具体的实现方式分析吧。 实现 仍然按照已有的编程经验...

Global site tag (gtag.js) - Google Analytics