List 列表
Redis列表是简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表的头部或者尾部
命令 | 描述 | 返回值 |
LPUSH | 插入到列表的头部,可同时插入多个元素 | 列表中元素数量 |
RPUSH | 插入到列表的尾部,可同时插入多个元素 | 列表中元素数量 |
LRANGE | 获取列表,参数是正值从左向右计算,是负值从右向左计算 | 返回范围内的列表元素 |
LPOP | 从头部获取第一个元素返回,并移除,不存在返回nil | 链表的头部元素 |
RPOP | 从尾部获取第一个元素返回,并移除,不存在返回nil | 链表的尾部部元素 |
LPOP是 redis lists的一个重要操作
lpush 与 rpush 与 lrang
127.0.0.1:6379> lpush jlist learn
(integer) 1
127.0.0.1:6379> lpush jlist redis
(integer) 2
127.0.0.1:6379> rpush jlist today
(integer) 3
127.0.0.1:6379> lrange jlist 0 1
1) "redis"
2) "learn"
127.0.0.1:6379> lrange jlist 0 4
1) "redis"
2) "learn"
3) "today"
lpop 与 rpop
127.0.0.1:6379> lrange mylist 0 4
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> lpop mylist
"c"
127.0.0.1:6379> lpop mylist
"b"
127.0.0.1:6379> lpop mylist
"a"
127.0.0.1:6379> lrange mylist 0 4 ## 以全部pop,mylist中内容为空
(empty list or set)
Redis lists 两个常用示例
- 记录用户的近期更新操作,日志
比如,在社交网站往往会显示用户的最新的照片;那么每当用户上传新的照片后,我们可以使用 lpush将 photo_id 存入list中;当用户访问页面时,我们使用lrange 0 5 来显示最新上传的5张照片
- 进程间数据传递
在consumer-producer 模型中,生产者将数据放入list,消费者获取这些数据执行一些操作
Redis保证这些操作可以信赖而且高效。
Capped lists 截取list
命令 | 描述 |
LTRIM | 保留LTRIM范围内的元素,在范围外的元素全部移除 |
LTRIM与LRANGE相似,都会返回范围内的list元素;但区别在于,LTRIM会将范围外的元素全部移除
127.0.0.1:6379> rpush mylist 1 2 3 4 5 6
(integer) 6
127.0.0.1:6379> ltrim mylist 0 2
OK
127.0.0.1:6379> lrange mylist 0 10
1) "1"
2) "2"
3) "3"
注:
虽然 LRANGE是时间复杂度为 O(N)的命令,无论是从头部还是从尾部获取小范围的list元素,其时间是一个常量
Blocking operations on lists 阻塞操作
Redis list的一个特点,可以去实现队列以及在交互系统中实现阻塞操作
假设,在producer/consumer模型中,producers 使用一个进程向list中写入(lpush)元素,consumers 使用一个不同的进程去读取元素(rpop)。我们可以想到consumers 可能pop不到元素,然后必须等一段时间后再次尝试去pop,于是就产生了轮询。
轮询的缺点:
- 强制 redis和客户端去执行一些没用的命令,因为当list为空的之后,并不能得到我们想要的数据
- 延长了获取数据时间,当第一次获取不到数据,可能会需要获取第二次 ,第三次…
那么,为了解决这个问题,redis提供了:
命令 | 描述 |
BLPOP | list为空,阻塞list,直到list中有一个可用元素;list不为空,返回头部第一个元素,并删除 |
BRPOP | list为空,阻塞list,直到list中有一个可用元素;list不为空,返回尾部第一个元素,并删除 |
BLPOP [key1,key2…] timeout 可获取多个key,阻塞时间
127.0.0.1:6379> brpop tasks 10 # tasks为空,阻塞等待10s,仍没有元素被push,返回nil
(nil)
(10.06s)
127.0.0.1:6379> brpop tasks 10 #tasks为空,阻塞等待10s,使用另一个进程lpush一个元素,被获取并返回
1) "tasks"
2) "1"
(4.92s)
若 timeout时间设置为 0,则该阻塞会一直等待。而且支持同时阻塞多个list,有一个阻塞获取到值,阻塞都会消失
阻塞命令特点:
- 执行阻塞的客户端是有顺序的,如果多个进程同时阻塞一个list,那么当list中lpush元素后,会优先被第一个阻塞进程获取,以此类推
- 返回元素是个数组:key和value,因为可能会阻塞多个list
- 当阻塞时间到了,返回null
列表间的数据pop
命令 | 描述 |
RPOPLPUSH source destination | 删除列表中的最后一个元素,将其追加到另一个列表(建立安全队列或者轮转队列) |
BRPOPLPUSH source destination timeout | 弹出列表的一个值,将它推到另一个列表,并返回这个值;list为空,则阻塞list直到有一个可用的元素 |
127.0.0.1:6379> lpush task1 1 ## task1中 push一个元素
(integer) 1
127.0.0.1:6379> rpoplpush task1 task2 ## task1中 追加到 task2中
"1"
127.0.0.1:6379> rpoplpush task1 task2 ## task1中没有元素了
(nil)
127.0.0.1:6379> lrange task2 0 2
1) "1"
127.0.0.1:6379> brpoplpush task1 task2 0 ## 阻塞追加,当另一个进程为task1 push一个元素2,阻塞结束
"2"
(15.81s)
Redis 自动创建和删除keys
在Redis我们不需要去创建空的list,其实当list没有元素,key会被redis删除。而且当我们向一个不存在的list中添加元素,redis会先为我们创建一个key;
这个Rules,同样适用于 sets ,sorted sets,hashes集合类型:
- 当我们向集合中添加元素,如果目标key不存在,一个空集合将会在添加元素前被创建
- 当我们对集合进行移除元素操作,如果元素全部被移除,则key也会被自动销毁
- 使用一些只读命令,如LLEN(返回集合长度)或者写入命令区删除元素,结果是一样的