BLPOP

用法
BLPOP key [ key ... ] timeout
复杂度
O(N),其中 N 是提供的键的数量。
起始版本
2.0.0
ACL 类别
@list, @write, @blocking, @slow

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

非阻塞行为

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

键会按照它们被提供的顺序进行检查。假设键 list1 不存在,而 list2list3 持有非空列表。考虑以下命令:

BLPOP list1 list2 list3 0

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

阻塞行为

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

一旦其中一个列表出现新数据,客户端将返回解除阻塞的键名和弹出的值。

BLPOP 导致客户端阻塞且指定了非零超时时,如果在指定超时时间内没有对至少一个指定键执行推送操作,客户端将解除阻塞并返回一个 nil 多批量值。

超时参数被解释为一个双精度浮点值,指定了最大阻塞秒数。超时设置为零可以用于无限期阻塞。

哪个键优先服务?哪个客户端?哪个元素?优先级排序细节。

  • 如果客户端尝试阻塞多个键,但至少一个键包含元素,则返回的键/元素对是从左到右第一个具有一个或多个元素的键。在这种情况下,客户端不会被阻塞。因此,例如 BLPOP key1 key2 key3 key4 0,假设 key2key4 都是非空的,将始终从 key2 返回一个元素。
  • 如果多个客户端为同一个键阻塞,则第一个被服务的客户端是等待时间最长的那个(第一个为该键阻塞的客户端)。一旦客户端解除阻塞,它将不再保留任何优先级;当它在下一次调用 BLPOP 时再次阻塞时,它将根据已为同一键阻塞的客户端数量进行服务,所有这些客户端都将在它之前被服务(从第一个阻塞的到最后一个阻塞的)。
  • 当一个客户端同时阻塞多个键,并且多个键同时有元素可用(因为事务或 Lua 脚本向多个列表添加了元素)时,客户端将使用第一个接收到推送操作的键解除阻塞(假设该键有足够的元素来服务我们的客户端,因为可能还有其他客户端也在等待此键)。基本上,在每个命令执行后,Valkey 将运行一个列表,包含所有接收到数据并且至少有一个客户端阻塞的键。该列表按新元素到达时间排序,从第一个接收到数据的键到最后一个。对于每个处理过的键,Valkey 将以 FIFO 方式服务所有等待该键的客户端,只要该键中还有元素。当键为空或不再有客户端等待该键时,将处理上一个命令/事务/脚本中接收到新数据的下一个键,依此类推。

当多个元素被推送到列表中时 !BLPOP 的行为。

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

  • 可变参数推送操作,例如 LPUSH mylist a b c
  • 在包含对同一列表的多个推送操作的 MULTI 块的 EXEC 之后。
  • 执行 Lua 脚本。

发生的情况是,执行多个推送的命令会先执行,**只有在** 命令执行之后,阻塞的客户端才会被服务。考虑以下命令序列。

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

如果上述情况发生在 Redis OSS 2.6 或更高版本的服务器上,客户端 **A** 将获得元素 c,因为 LPUSH 命令执行后,列表包含 c,b,a,所以从左侧获取元素意味着返回 c

请注意,出于同样的原因,Lua 脚本或 MULTI/EXEC 块可能会将元素推送到列表中,然后 **删除该列表**。在这种情况下,阻塞的客户端将根本不会被服务,并且只要在单个命令、事务或脚本执行后列表中没有数据,它们将继续保持阻塞状态。

!BLPOP!MULTI / !EXEC 事务中

BLPOP 可以与流水线(发送多个命令并批量读取回复)一起使用,然而这种设置几乎只在它作为流水线的最后一个命令时才有意义。

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

如果你喜欢科幻小说,可以想象在 MULTI / EXEC 块中时间以无限速度流逝...

示例

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

可靠队列

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

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

模式:事件通知

使用阻塞列表操作可以实现不同的阻塞原语。例如,对于某些应用程序,您可能需要阻塞等待 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

RESP2 回复

以下之一

  • 空回复:没有元素可以弹出且超时已过期

  • 数组回复:弹出元素的键和弹出元素的值。

RESP3 回复

以下之一

  • 空回复:没有元素可以弹出且超时已过期

  • 数组回复:弹出元素的键和弹出元素的值。

历史

版本 变更
6.0.0

timeout 被解释为双精度浮点数而不是整数。