本文内容为 http://www.redis.io/commands/blpop 的翻译、注解、例子扩充及其它修改。感谢 Redis 作者 Antirez 为开源社区作出的贡献,本文保证最新、最准、最全以表示对其的敬意。欢迎留言纠错、提示更新或支持。
BLPOP key [key ...] timeout

命令 BLPOP 是一条阻塞式(Blocking)列表弹出(Pop)原语(Primitive)

BLPOP is a blocking list pop primitive

它是命令 LPOP 的带阻塞功能版本,因为当其发现所有给定列表都不能弹出元素时,将会阻塞当前连接(Connection)

It is the blocking version of LPOP because it blocks the connection when there are no elements to pop from any of the given lists.

一个元素将从第一个非空列表的头部(Head)弹出,且按命令中所给定的顺序对所有键进行检测。

An element is popped from the head of the first list that is non-empty, with the given keys being checked in the order that they are given.
  • 返回一组响应,根据不同情况明确地分为以下结果:

    • 当没有元素可以被弹出,且设置的过期时间到期时,返回 nil
    • 如果返回的结果包含两个部份,第一个部位为从中弹出一个元素的键的名字(Name),而第二部份为所弹出元素的值(Value)
    Array reply: specifically:
    • A nil multi-bulk when no element could be popped and the timeout expired.
    • A two-element multi-bulk with the first element being the name of the key where an element was popped and the second element being the value of the popped element.
  • redis> DEL list1 list2
    (integer) 0
    redis> RPUSH list1 a b c
    (integer) 3
    redis> BLPOP list1 list2 0
    1) "list1"
    2) "a"
  • 当命令 BLPOP 被调用时,如果至少存在一个指定的键包含一个非空列表,一个元素将会从列表的头部弹出,且与对应的列的键名一起共同返回给调用者(Caller)

    When BLPOP is called, if at least one of the specified keys contains a non-empty list, an element is popped from the head of the list and returned to the caller together with the key it was popped from.

    所有键将被按命令中所给定的顺序进行检测。

    Keys are checked in the order that they are given.

    让我们假设键 list1 不存在,且键 list2 及键 list3 所对应的列表非空,这个时候,执行以下命令时:

    BLPOP list1 list2 list3 0

    命令 BLPOP 保证从存储在键 list2 中的列表中返回一个元素(因为在按 list1list2list3 顺序检测所有列表时,list2 为第一个非空列表)。

    Let's say that the key list1 doesn't exist and list2 and list3 hold non-empty lists. Consider the following command:

    BLPOP list1 list2 list3 0

    BLPOP guarantees to return an element from the list stored at list2 (since it is the first non empty list when checking list1, list2 and list3 in that order).

  • 如果指定的键没有一个存在,命令 BLPOP 将会一直阻塞当前连接,直到另一个客户端程序(Client)对其中的某个键进行一次 LPUSHRPUSH 操作。

    If none of the specified keys exist, BLPOP blocks the connection until another client performs an LPUSH or RPUSH operation against one of the keys.

    一旦新的数据出现在其中某个列表上,当前客户端将会返回使其解阻塞(Unblock)的键的名字,以及对应的弹出的值。

    Once new data is present on one of the lists, the client returns with the name of the key unblocking it and the popped value.

    当命令 BLPOP 引起客户端阻塞,且指定了一个非 0(Non-zero)的超时时间(Timeout)时,当指定超时时间到期(Expired),而在此之前不存在任何一列表被压入(Push)某个元素,当前客户端将会返回一个 nil 值。

    When BLPOP causes a client to block and a non-zero timeout is specified, the client will unblock returning a nil multi-bulk value when the specified timeout has expired without a push operation against at least one of the specified keys.

    timeout 参数被解析为用于指定最大阻塞秒(Second)数的一个整数(Integer)如果超时时间被设置为 0,将会无限期阻塞。

    The timeout argument is interpreted as an integer value specifying the maximum number of seconds to block. A timeout of zero can be used to block indefinitely.
  • What key is served first? What client? What element? Priority ordering details.

    • If the client tries to blocks for multiple keys, but at least one key contains elements, the returned key / element pair is the first key from left to right that has one or more elements. In this case the client is not blocked. So for instance BLPOP key1 key2 key3 key4 0, assuming that both key2 and key4 are non-empty, will always return an element from key2.
    • If multiple clients are blocked for the same key, the first client to be served is the one that was waiting for more time (the first that blocked for the key). Once a client is unblocked it does not retain any priority, when it blocks again with the next call to BLPOP it will be served accordingly to the number of clients already blocked for the same key, that will all be served before it (from the first to the last that blocked).
    • When a client is blocking for multiple keys at the same time, and elements are available at the same time in multiple keys (because of a transaction or a Lua script added elements to multiple lists), the client will be unblocked using the first key that received a push operation (assuming it has enough elements to serve our client, as there may be other clients as well waiting for this key). Basically after the execution of every command Redis will run a list of all the keys that received data AND that have at least a client blocked. The list is ordered by new element arrival time, from the first key that received data to the last. For every key processed, Redis will serve all the clients waiting for that key in a FIFO fashion, as long as there are elements in this key. When the key is empty or there are no longer clients waiting for this key, the next key that received new data in the previous command / transaction / script is processed, and so forth.
  • Behavior of BLPOP when multiple elements are pushed inside a list.

    There are times when a list can receive multiple elements in the context of the same conceptual command:
    • Variadic push operations such as LPUSH mylist a b c.
    • After an EXEC of a MULTI block with multiple push operations against the same list.
    • Executing a Lua Script with Redis 2.6 or newer.
    When multiple elements are pushed inside a list where there are clients blocking, the behavior is different for Redis 2.4 and Redis 2.6 or newer.
    For Redis 2.6 what happens is that the command performing multiple pushes is executed, and only after the execution of the command the blocked clients are served. Consider this sequence of commands.
    Client A:   BLPOP foo 0
    Client B:   LPUSH foo a b c
    If the above condition happens using a Redis 2.6 server or greater, Client A will be served with the c element, because after the LPUSH command the list contains c,b,a, so taking an element from the left means to return c.
    Instead Redis 2.4 works in a different way: clients are served in the context of the push operation, so as long as LPUSH foo a b c starts pushing the first element to the list, it will be delivered to the Client A, that will receive a (the first element pushed).
    The behavior of Redis 2.4 creates a lot of problems when replicating or persisting data into the AOF file, so the much more generic and semantically simpler behaviour was introduced into Redis 2.6 to prevent problems.
    Note that for the same reason a Lua script or a MULTI/EXEC block may push elements into a list and afterward delete the list. In this case the blocked clients will not be served at all and will continue to be blocked as long as no data is present on the list after the execution of a single command, transaction, or script.
  • BLPOP inside a MULTI / EXEC transaction

    BLPOP can be used with pipelining (sending multiple commands and reading the replies in batch), however this setup makes sense almost solely when it is the last command of the pipeline.
    Using BLPOP inside a MULTI / EXEC block does not make a lot of sense as it would require blocking the entire server in order to execute the block atomically, which in turn does not allow other clients to perform a push operation. For this reason the behavior of BLPOP inside MULTI / EXEC when the list is empty is to return a nil multi-bulk reply, which is the same thing that happens when the timeout is reached.
    If you like science fiction, think of time flowing at infinite speed inside a MULTI / EXEC block...
  • Reliable queues

    When BLPOP returns an element to the client, it also removes the element from the list. This means that the element only exists in the context of the client: if the client crashes while processing the returned element, it is lost forever.
    This can be a problem with some application where we want a more reliable messaging system. When this is the case, please check the BRPOPLPUSH command, that is a variant of BLPOP that adds the returned element to a target list before returning it to the client.
  • Pattern: Event notification

    Using blocking list operations it is possible to mount different blocking primitives. For instance for some application you may need to block waiting for elements into a Redis Set, so that as far as a new element is added to the Set, it is possible to retrieve it without resort to polling. This would require a blocking version of SPOP that is not available, but using blocking list operations we can easily accomplish this task.
    The consumer will do:
    LOOP forever
        WHILE SPOP(key) returns elements
            ... process elements ...
        END
        BRPOP helper_key
    END
    While in the producer side we'll use simply:
    MULTI
    SADD key element
    LPUSH helper_key x
    EXEC
  • 版本支持

    2.0.0+

    时间复杂度(Time complexity)

    O(1)