BLPOP

删除并返回列表中的第一个元素。否则将阻塞,直到元素可用为止。如果弹出最后一个元素,则删除列表。

语法

BLPOP key [key ...] timeout

引入版本:2.0.0

复杂度摘要:O(N)

[!NOTE] 此命令的行为在集群 Redis 环境中有所不同。请参阅 多键操作 页面了解更多信息。

BLPOP 是阻塞列表弹出原语。它是 LPOP 的阻塞版本,因为当没有任何元素可从任何给定列表中弹出时,它会阻塞连接。从第一个非空列表的头部弹出一个元素,并按照给出的顺序检查给定的键。

必需参数

key [key ...]

列表中的一个或多个按键进行操作。

timeout

最大阻塞时间,单位为秒。 0 超时会无限期地阻塞。

示例

redis> DEL list1 list2
(integer) 0
redis> RPUSH list1 a b c
(integer) 3
redis> BLPOP list1 list2 0
1) "list1"
2) "a"

详细说明

非阻塞行为

当调用 BLPOP 时,如果指定的键中至少有一个包含非空列表,则从列表的头部弹出一个元素,并将其与从中弹出的 key 一起返回给调用者。

键按照给出的顺序进行检查。假设键 list1 不存在,并且 list2 和 list3 包含非空列表。考虑以下命令:

BLPOP list1 list2 list3 0

BLPOP 保证从存储在 list2 的列表中返回一个元素(因为在按顺序检查 list1、list2 和 list3 时,它是第一个非空列表)。

阻塞行为

如果指定的键都不存在,则 BLPOP 会阻止连接,直到另一个客户端针对其中一个键执行 LPUSH 或 RPUSH 操作。

一旦列表之一出现新数据,客户端就会返回解锁该数据的键的名称以及弹出的值。

当 BLPOP 导致客户端阻塞并且指定了非零超时时,客户端将在指定超时到期且未针对至少一个指定键执行推送操作时解除阻塞,返回 nil 多批量值。

超时参数被解释为双精度值,指定要阻止的最大秒数。超时为零可用于无限期阻塞。

首先按哪个键?什么客户?什么元素?优先订购详细信息。

  • 如果客户端尝试阻止多个键,但至少有一个键包含元素,则返回的键/元素对是从左到右第一个包含一个或多个元素的键。在这种情况下,客户端不会被阻止。例如,BLPOP key1 key2 key3 key4 0,假设 key2 和 key4 均非空,则始终从 key2 返回一个元素。

  • 如果多个客户端因同一键而被阻塞,则第一个被服务的客户端是等待时间最长的客户端(第一个因该键而阻塞的客户端)。一旦客户端被解除阻止,它就不再保留任何优先级;当它再次阻塞另一个 BLPOP 调用时,它将根据其在队列中的新位置提供服务。

  • 当客户端阻塞多个键并且多个键因同一命令、事务或 Lua 脚本而变为非空时,将根据 BLPOP 调用中的按键顺序 为客户端提供服务,而不是根据写入操作的顺序。写入发生后,Redis 会重新处理客户端的阻塞命令,并从键列表中的 第一个非空键 中弹出。
    例如,如果 key1 和 key2 在同一个 MULTI/EXEC 事务期间都接收到元素,则在 BLPOP key1 key2 0 上阻塞的客户端将从 key1 中弹出,因为 key1 首先出现。

在内部,当写入使阻塞的客户端取得进展时,Redis 会将该客户端标记为未阻塞(将其添加到内部队列)。不会立即发送回复。在服务器进入空闲状态之前(在 beforeSleep() 阶段),Redis 会重新检查阻塞命令,并根据其提供的键列表中的第一个非空键为客户端提供服务。

示例

客户A

BLPOP key1 key2 0

客户B

MULTI
RPUSH key2 1 2 3 4
RPUSH key1 5 6 7
EXEC

虽然 key2 在事务内部首先被压入,但在事务完成后,Redis 会重新处理客户端 A 的阻塞命令。
此时两个列表都是非空的,BLPOP 从其参数列表中的第一个非空键(key1)弹出:

"key1"
"5"

要使 Redis 从 key2 弹出,请颠倒阻塞调用中键的顺序:

BLPOP key2 key1 0

将多个元素推入列表时 BLPOP 的行为。

有时列表可以在同一概念命令的上下文中接收多个元素:

  • 可变参数推送操作,例如 LPUSH mylist a b c。
  • 在 MULTI 块的 EXEC 对同一列表进行多次推送操作之后。
  • 使用 Redis 2.6 或更高版本执行 Lua 脚本。

当多个元素被推送到存在客户端阻塞的列表中时,Redis 2.4 和 Redis 2.6 或更高版本的行为有所不同。

对于 Redis 2.6,会执行执行多次推送的命令,并执行 仅在之后 为被阻止的客户端提供服务的命令。考虑这个命令序列。

Client A:   BLPOP foo 0
Client B:   LPUSH foo a b c

如果使用 Redis 2.6 或更高版本的服务器发生上述情况,客户端 A 将收到 c 元素,因为在 LPUSH 命令之后列表包含 c,b,a,因此从左侧获取元素意味着返回 c。

相反,Redis 2.4 以不同的方式工作:客户端接受推送操作的 在上下文中,因此只要 LPUSH foo a b c 开始将第一个元素推送到列表,它将被传递到客户端 A,客户端将收到 a(推送的第一个元素)。

当将数据复制或保存到 AOF 文件中时,Redis 2.4 的行为会产生很多问题,因此 Redis 2.6 中引入了更通用且语义更简单的行为来防止出现问题。

请注意,出于同样的原因,Lua 脚本或 MULTI/EXEC 块可能会将元素推入列表,然后推入 删除列表。在这种情况下,被阻止的客户端将根本不会得到服务,并且只要在执行单个命令、事务或脚本后列表中不存在任何数据,就会继续被阻止。

MULTI / EXEC 交易中的 BLPOP

BLPOP 可以与管道一起使用(发送多个命令并批量读取回复),但是此设置几乎仅在它是管道的最后一个命令时才有意义。

在 MULTI / EXEC 块内使用 BLPOP 没有多大意义,因为它需要阻止整个服务器才能原子执行该块,而这又不允许其他客户端执行推送操作。因此,当列表为空时,MULTI / EXEC 内的 BLPOP 的行为是返回 nil 多批量回复,这与达到超时时发生的情况相同。

如果您喜欢科幻小说,请想象时间在 MULTI / EXEC 块内以无限速度流动......

可靠的队列

当BLPOP向客户端返回一个元素时,它也会从列表中删除该元素。这意味着该元素仅存在于客户端的上下文中:如果客户端在处理返回的元素时崩溃,则该元素将永远丢失。

对于某些我们需要更可靠的消息传递系统的应用程序来说,这可能是一个问题。在这种情况下,请检查 BRPOPLPUSH 命令,该命令是 BLPOP 的变体,它将返回的元素添加到目标列表中,然后再将其返回给客户端。

模式:事件通知

使用阻塞列表操作可以安装不同的阻塞原语。例如,对于某些应用程序,您可能需要阻止等待元素进入 Redis Set,以便只要将新元素添加到 Set 中,就可以检索它而无需诉诸轮询。这需要 SPOP 的阻塞版本,但该版本不可用,但使用阻塞列表操作我们可以轻松完成此任务。

消费者会:

LOOP forever
    WHILE SPOP(key) returns elements
        ... process elements ...
    END
    BRPOP helper_key
END

在生产者方面,我们将简单地使用:

MULTI
SADD key element
LPUSH helper_key x
EXEC

Redis Software 与 Redis Cloud 兼容性

Redis
软件
Redis
Cloud
说明
✅ 标准
✅ 主动-主动
✅ 标准
✅ 主动-主动

返回值

RESP2

以下之一: * 无回复:无法弹出元素且超时已过 * 数组回复:弹出元素的键以及弹出元素的值。

RESP3

以下之一: * 空回复:无法弹出元素且超时已过 * 数组回复:弹出元素的键以及弹出元素的值。

资料来源:Redis 官方 BLPOP 文档;中文内容参考 Redis 文档许可。