暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis每日一练(26):BLPOP和BRPOP命令

原创 AlbertS 2019-12-28
6660

版权声明: 转载请注明出处!本文采用 知识共享 署名-非商业性使用-禁止演绎 4.0 国际许可协议

前言

今天学习的这两个命令是学习 Redis 命令以来第一次用到阻塞概念,什么是阻塞?就是在调用函数的时候,如果不能马上得到想要的,就开始等待的状态,并不返回数据,当条件满足后立即返回,这就是函数阻塞,这篇笔记之前总结的命令都是非阻塞的,也就是无论有无结果都会立即返回,接下来具体看一下今天的这两个阻塞命令。

这篇笔记中的2个命令分别是 BLPOP 、 BRPOP ,可以参考:

BLPOP

  • 最早出现版本:2.0.0
  • 时间复杂度:O(1)
  • 命令参数:BLPOP key [key …] timeout
  • 操作类型:lists
  • 官方文档

作用

BLPOP 命令是 LPOP 命令的阻塞版本,也是从列表的头部弹出一个元素,不同的是 LPOP 命令如果指定的弹出列表不存在或者为空,则直接返回,而 BLPOP 命令如果指定的弹出列表不存在或者为空,则会一直等待到超时时间返回(nil)或者一直等到列表中被其他链接插入元素时,再弹出返回。

还有一点不同是 LPOP 命令只能指定一个参数,弹出一个列表的表头,但是 BLPOP 命令后面可以跟多个列表,有一个满足弹出条件的就可以直接弹出返回。

BLPOP 命令最后一个参数 timeout 是超时时间,单位是秒,如果 timeout 大于0,则到达指定的秒数即使没有弹出成功也会返回,如果 timeout 的值为0,则会一直阻塞等待其他连接向列表中插入元素, timeout 参数不允许为负数。

BLPOP 命令上面提到可以跟多个列表参数,其顺序是从左往右依次判断的,找到一个非空的列表就会立即返回,如果所有的列表都不存在或者为空,则阻塞等待,正常返回时返回的类型是一个列表,一共包含两个值,第一个是操作弹出的列表,第二个是弹出的元素。

这样描述起来可能会有点迷糊,接下来我们写几个例子测试一下,理解一下 BLPOP 命令的阻塞型行为。

练习

当两个列表都有元素的时候,不会产生阻塞行为,优先弹出第一个列表中的元素:

127.0.0.1:6379> LPUSH cache a b c e e F g 3 h
(integer) 9
127.0.0.1:6379> LRANGE cache 0 -1
1) "h"
2) "3"
3) "g"
4) "F"
5) "e"
6) "e"
7) "c"
8) "b"
9) "a"
127.0.0.1:6379> LPUSH cachelist good man
(integer) 2
127.0.0.1:6379> LRANGE cachelist 0 -1
1) "man"
2) "good"
127.0.0.1:6379> BLPOP cache cachelist 0
1) "cache"
2) "h"
127.0.0.1:6379> BLPOP cachelist cache 1
1) "cachelist"
2) "man"
127.0.0.1:6379>

第一个列表中有元素,第二个列表不存在时,会直接弹出第一个列表中的元素,然后直接返回,当第一个列表不存在第二个列表包含元素时,就会从第二个列表中弹出元素直接返回:

127.0.0.1:6379> BLPOP cache nolist 0
1) "cache"
2) "3"
127.0.0.1:6379> BLPOP nolist cache 10
1) "cache"
2) "g"
127.0.0.1:6379>

当指定的列表中都不存在元素时, BLPOP 命令会阻塞客户端连接,直到超时时间到返回(nil):

127.0.0.1:6379> BLPOP nolist 10
(nil)
(10.02s)
127.0.0.1:6379>

上面的命令等待了10.02秒之后直接返回了nil,接下来将超时时间填成0再测试一下:

127.0.0.1:6379> BLPOP nolist 0

输入之后就没有反应了,实际上这就是阻塞状态,现在打开另一个连接,然后将刚才的列表 nolist 插入一个元素,查询一下:

127.0.0.1:6379> LPUSH nolist new
(integer) 1
127.0.0.1:6379> LRANGE nolist 0 -1
(empty list or set)
127.0.0.1:6379>

很奇怪是不是,为什么刚刚插入一个元素,再查询居然没有了,转回去再看下刚才的客户端连接发现已经返回了:

127.0.0.1:6379> BLPOP nolist 0
1) "nolist"
2) "new"
(195.46s)
127.0.0.1:6379>

原来刚刚插入的元素 new 被另一个连接中的 BLPOP 阻塞命令给弹出了,在等待了195.46s之后返回了。

因为这个命令是阻塞的,就会涉及到顺序问题,比如一个连接A对空列表执行了命令 BLPOP nolist 0,然后连接B也对空列表执行了命令 BLPOP nolist 0,那么这两个连接都会被阻塞,当有其他的连接向列表 nolist 插入一个元素是,究竟哪个连接该返回呢?还是同时返回?

Redis 的处理方法是维护一个阻塞队列,提供先阻塞先服务的机制,当多个阻塞同时满足唤醒条件时,先阻塞的命令被优先唤醒。

BRPOP

  • 最早出现版本:2.0.0
  • 时间复杂度:O(1)
  • 命令参数:BRPOP key [key …] timeout
  • 操作类型:lists
  • 官方文档

作用

这个命令与 BLPOP 命令基本相同,唯一的区别就是这个命令的弹出操作是从列表尾部弹出,而 BLPOP 命令是从列表头部弹出,其他的注意事项参考 BLPOP 命令的总结就可以。

练习

启动A连接在一个不存在的空的list上执行 BRPOP 操作,会立即进入阻塞状态:

127.0.0.1:6379> LRANGE nolist 0 -1
(empty list or set)
127.0.0.1:6379> BRPOP nolist 0

启动连接B向列表 nolist 中插入元素,查看列表内容:

127.0.0.1:6379> RPUSH nolist good
(integer) 1
127.0.0.1:6379> LRANGE nolist 0 -1
(empty list or set)
127.0.0.1:6379>

插入元素后查看列表元素为空,返回到A连接看到原来的 BRPOP 命令已经返回:

127.0.0.1:6379> BRPOP nolist 0
1) "nolist"
2) "good"
(67.51s)
127.0.0.1:6379>

总结

  1. BLPOP 命令可以弹出指定列表中的头部的元素,若所有的列表均不存在或者为空,则阻塞等待。
  2. BRPOP 命令与 BLPOP 基本一样,只是弹出列表尾部的元素,正常弹出时返回两个值,第一个值是弹出的列表,第二个值是弹出的元素

2019-12-14 15:42:33

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论