# BLPOP

移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 语法

BLPOP key [key ...] timeout
  • 可用版本:

    2.0.0

  • 时间复杂度:

    O(N) 其中 N 是提供的密钥的数量。

  • ACL 类别:

    @write, @list, @slow, @blocking

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

# 非阻塞行为

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

密钥按照给出的顺序进行检查。假设密钥list1不存在list2并且list3持有非空列表。考虑以下命令:

BLPOP list1 list2 list3 0

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

# 阻止行为

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

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

BLPOP导致客户端阻塞并指定非零超时时,客户端将nil在指定的超时已过期且没有针对至少一个指定键的推送操作时解除阻塞返回一个多批量值。

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

# 首先提供什么密钥?什么客户?什么元素?优先订购详情。

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

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

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

  • 可变推操作,例如LPUSH mylist a b c.
  • 在对同一个列表进行多次推送操作EXEC的块之后。MULTI
  • 使用 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 或更高版本的服务器发生上述情况,则将为客户端Ac提供该元素,因为在LPUSH命令之后列表包含c,b,a,因此从左侧取一个元素意味着返回c

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

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

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

# BLPOPMULTI/EXEC交易里面

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

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

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

# 返回

数组回复:具体来说:

  • nil当没有元素可以弹出并且超时过期时的多批量。
  • 一个双元素多块,第一个元素是弹出元素的键的名称,第二个元素是弹出元素的值。

# 例子

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 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 版本 6.0.0 开始:timeout被解释为双精度而不是整数。

# 反馈

如果您在此页面上发现问题,或有改进建议,请提交请求以合并或打开存储库中的问题。

Last Updated: 4/18/2023, 8:45:33 AM