BLPOP

语法
BLPOP key [key ...] timeout
可用自
2.0.0
时间复杂度
O(N),其中 N 是提供的键的数量。
ACL 类别
@write, @list, @slow, @blocking,

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 脚本将元素添加到多个列表中),客户端将使用第一个接收到推送操作的键进行解阻塞(假设该键有足够的元素来服务我们的客户端,因为可能还有其他客户端在等待该键)。基本上,在执行每个命令后,Redis 将运行一个列表,其中包含所有接收到数据的键,并且至少有一个客户端处于阻塞状态。该列表按新元素到达时间排序,从第一个接收到数据的键到最后一个键。对于每个处理的键,Redis 将以 FIFO 方式为所有等待该键的客户端服务,只要该键中还有元素。当该键为空或不再有客户端等待该键时,将处理在之前的命令/事务/脚本中接收到新数据的下一个键,依此类推。

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(第一个推送到列表中的元素)。

Redis 2.4 的行为在复制或将数据持久化到 AOF 文件时会导致很多问题,因此在 Redis 2.6 中引入了更通用的语义上更简单的行为来防止这些问题。

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

MULTI / EXEC 事务中的 BLPOP

BLPOP 可以与流水线(发送多个命令并批处理读取回复)一起使用,但是这种设置几乎只在它时才有意义是管道中的最后一个命令。

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

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

示例

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

可靠的队列

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

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

模式:事件通知

使用阻塞列表操作,可以挂载不同的阻塞原语。例如,对于某些应用程序,您可能需要阻塞等待 Redis 集合作中的元素,以便只要将新元素添加到集合中,就可以检索该元素,而无需使用轮询。这将需要一个阻塞版本的 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 回复

以下之一

  • 空回复:无法弹出元素,并且超时过期
  • 数组回复:弹出元素的键以及弹出元素的值。

历史记录

  • 从 Redis 版本 6.0.0 开始:timeout 被解释为双精度数而不是整数。
RATE THIS PAGE
Back to top ↑