BLPOP
BLPOP key [key ...] timeout
- Available since:
- 2.0.0
- Time complexity:
- O(N) where N is the number of provided keys.
- ACL categories:
-
@write
,@list
,@slow
,@blocking
,
BLPOP
是一个阻塞列表弹出原语。
它是 LPOP
的阻塞版本,因为当没有任何元素可以从给定的列表中弹出时,它会阻塞连接。
元素从第一个非空列表的头部弹出,给定的键按照它们被给定的顺序进行检查。
非阻塞行为
当调用BLPOP
时,如果至少有一个指定的键包含非空列表,则从列表的头部弹出一个元素,并将其与弹出的key
一起返回给调用者。
键的检查顺序是按照它们被给出的顺序进行的。
假设键 list1
不存在,而 list2
和 list3
包含非空列表。
考虑以下命令:
BLPOP list1 list2 list3 0
BLPOP
保证会返回存储在 list2
中的列表的一个元素(因为按照 list1
、list2
和 list3
的顺序检查时,它是第一个非空列表)。
阻塞行为
如果指定的键都不存在,BLPOP
会阻塞连接,直到另一个客户端对其中一个键执行LPUSH
或RPUSH
操作。
一旦其中一个列表上出现新数据,客户端将返回解除阻塞的键名和弹出的值。
当BLPOP
导致客户端阻塞并且指定了非零超时时,如果在指定的超时时间内没有对至少一个指定键执行推送操作,客户端将解除阻塞并返回一个nil
多批量值。
timeout参数被解释为一个双精度值,指定阻塞的最大秒数。超时值为零可用于无限期阻塞。
首先提供什么键?什么客户端?什么元素?优先级排序详情。
- 如果客户端尝试为多个键进行阻塞,但至少有一个键包含元素,则返回的键/元素对是从左到右第一个包含一个或多个元素的键。在这种情况下,客户端不会被阻塞。例如,
BLPOP key1 key2 key3 key4 0
,假设key2
和key4
都不为空,将始终从key2
返回一个元素。 - 如果多个客户端被阻塞在同一个键上,第一个被服务的客户端是等待时间最长的那个(即第一个阻塞在该键上的客户端)。一旦客户端被解除阻塞,它不会保留任何优先级,当它在下一次调用
BLPOP
时再次阻塞,它将根据已经阻塞在该键上的客户端数量被服务,这些客户端都会在它之前被服务(从第一个阻塞的到最后一个阻塞的)。 - 当客户端同时阻塞多个键时,并且多个键中同时有元素可用(因为事务或Lua脚本向多个列表添加了元素),客户端将使用第一个接收到推送操作的键解除阻塞(假设它有足够的元素来服务我们的客户端,因为可能还有其他客户端也在等待这个键)。基本上,在执行每个命令后,Redis将运行一个包含所有接收到数据并且至少有一个客户端阻塞的键的列表。该列表按新元素到达时间排序,从第一个接收到数据的键到最后一个。对于每个处理的键,只要该键中有元素,Redis将以FIFO方式服务所有等待该键的客户端。当该键为空或不再有客户端等待该键时,将处理在前一个命令/事务/脚本中接收到新数据的下一个键,依此类推。
当多个元素被推入列表时,BLPOP
的行为。
有时候,在同一个概念命令的上下文中,列表可以接收多个元素:
当多个元素被推入一个列表,并且有客户端在阻塞时,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
块可能会将元素推入列表,然后删除列表。在这种情况下,被阻塞的客户端将完全不会被服务,并且只要在执行单个命令、事务或脚本后列表中没有数据,它们将继续被阻塞。
BLPOP
在 MULTI
/ EXEC
事务内部
BLPOP
可以与管道一起使用(发送多个命令并批量读取回复),然而这种设置几乎只在它是管道的最后一个命令时才有意义。
在MULTI
/ EXEC
块中使用BLPOP
没有太大意义,因为它需要阻塞整个服务器以原子方式执行该块,这反过来又不允许其他客户端执行推送操作。因此,当列表为空时,BLPOP
在MULTI
/ EXEC
中的行为是返回一个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 回复
以下之一:
- Nil reply: 没有元素可以弹出并且超时已过期
- Array reply: 弹出元素的键和弹出元素的值。
RESP3 回复
以下之一:
- Null reply: 没有元素可以弹出并且超时已过期
- Array reply: 弹出元素的键和弹出元素的值。
历史
- 从 Redis 版本 6.0.0 开始:
timeout
被解释为双精度浮点数而不是整数。