Redis中RPOP、BRPOP、LPOP和BLPOP使用示例代码实用指南
平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“Redis中RPOP、BRPOP、LPOP和BLPOP采用示例代码”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
核心概念:列表的方向
在深入命令之前,必须明确 Redis 列表的“方向”概念:
- 头部 (Left/Head): 列表的起始端。
- 尾部 (Right/Tail): 列表的结束端。
想象一个列表 ["A", "B", "C"]:
- 头部是
"A"。 - 尾部是
"C"。
1.RPOP: 从尾部弹出 (非阻塞)
命令:RPOP key
功能:移除同时得到列表 key 的最后一个元素(即尾部元素)。
阻塞:否。这是一个立即得到的命令。
得到值:
- 如果列表存在且非空:得到被弹出的元素。
- 如果列表不存在或为空:得到
nil。
采用场景:当你需一个轻松的栈 (Stack) 数据结构时(后进先出,LIFO)。
示例:
# 创建一个列表
127.0.0.1:6379> RPUSH mylist "A" "B" "C"
(integer) 3
# 查看列表内容
127.0.0.1:6379> LRANGE mylist 0 -1
1) "A"
2) "B"
3) "C"
# 执行 RPOP,弹出尾部元素 "C"
127.0.0.1:6379> RPOP mylist
"C"
# 再次查看,"C" 已被移除
127.0.0.1:6379> LRANGE mylist 0 -1
1) "A"
2) "B"
# 再次 RPOP,弹出 "B"
127.0.0.1:6379> RPOP mylist
"B"
# 列表为空时,返回 nil
127.0.0.1:6379> RPOP mylist
(nil)
2.BRPOP: 从尾部弹出 (阻塞)
命令:BRPOP key [key ...] timeout
功能:RPOP 的阻塞版本。它会移除同时得到列表的最后一个元素。如果所有给定的列表都为空,它会阻塞连接,直到有元素可用或超时。
阻塞:是。这是其核心特性。
得到值:
- 成功弹出:得到一个包含两个元素的数组
[key, value]。 - 超时:得到
nil。
采用场景:实现消费者,用来任务队列或消息队列,避免轮询。
示例:
终端 A (消费者):
# 尝试从 mylist 弹出元素,最多阻塞 5 秒
127.0.0.1:6379> BRPOP mylist 5
(等待中...)
终端 B (生产者):
# 向 mylist 推送一个新元素
127.0.0.1:6379> LPUSH mylist "New Task"
(integer) 1
终端 A (消费者):
# 立即收到响应
1) "mylist" # 元素来自哪个键
2) "New Task" # 被弹出的元素值
超时示例:
# 5秒内没有任何元素被推入
127.0.0.1:6379> BRPOP emptylist 5
(nil)
(5.04s)
3.LPOP: 从头部弹出 (非阻塞)
命令:LPOP key
功能:移除同时得到列表 key 的第一个元素(即头部元素)。
阻塞:否。
得到值:
- 如果列表存在且非空:得到被弹出的元素。
- 如果列表不存在或为空:得到
nil。
采用场景:与 RPOP 相反,如果你将列表用作栈,同时希望从另一端操作。
示例:
# 使用之前的列表 ["A", "B"]
127.0.0.1:6379> LRANGE mylist 0 -1
1) "A"
2) "B"
# 执行 LPOP,弹出头部元素 "A"
127.0.0.1:6379> LPOP mylist
"A"
# 列表现在只剩下 ["B"]
127.0.0.1:6379> LRANGE mylist 0 -1
1) "B"
4.BLPOP: 从头部弹出 (阻塞)
命令:BLPOP key [key ...] timeout
功能:LPOP 的阻塞版本。它会移除同时得到列表的第一个元素。如果所有给定的列表都为空,它会阻塞连接,直到有元素可用或超时。
阻塞:是。
得到值:
- 成功弹出:得到一个包含两个元素的数组
[key, value]。 - 超时:得到
nil。
采用场景:这是最常用的队列消费模式。配合 RPUSH(从尾部推入),能够完美实现先进先出 (FIFO) 的队列。
示例 (FIFO 队列):
生产者:
# 依次将任务推入队列尾部
127.0.0.1:6379> RPUSH task_queue "Task-1"
(integer) 1
127.0.0.1:6379> RPUSH task_queue "Task-2"
(integer) 2
消费者:
# 从队列头部阻塞式地获取任务
127.0.0.1:6379> BLPOP task_queue 0
1) "task_queue"
2) "Task-1" # 最先推入的任务最先被消费
# 再次执行,获取下一个任务
127.0.0.1:6379> BLPOP task_queue 0
1) "task_queue"
2) "Task-2"
Python示例代码
首先,请确保你已经安装了 redis 库:
pip install redis
1. 基础设置
落到代码里,我们先新建一个 Redis 连接,同时定义一个辅助函数来清理测试用的 key。
import redis
import time
import threading
# 创建 Redis 连接
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
def cleanup_keys(*keys):
"""清理测试用的 keys"""
r.delete(*keys)
2.RPOP和LPOP示例 (非阻塞)
这两个命令会立即得到结果,无论列表是否为空。
# 清理环境
cleanup_keys('test_list')
# 向列表中添加元素
r.rpush('test_list', 'A', 'B', 'C')
print("初始列表:", r.lrange('test_list', 0, -1)) # ['A', 'B', 'C']
# LPOP: 从头部弹出
head_element = r.lpop('test_list')
print("LPOP 弹出:", head_element) # A
print("LPOP 后列表:", r.lrange('test_list', 0, -1)) # ['B', 'C']
# RPOP: 从尾部弹出
tail_element = r.rpop('test_list')
print("RPOP 弹出:", tail_element) # C
print("RPOP 后列表:", r.lrange('test_list', 0, -1)) # ['B']
# 对空列表操作
empty_lpop = r.lpop('empty_list')
empty_rpop = r.rpop('empty_list')
print("空列表 LPOP:", empty_lpop) # None
print("空列表 RPOP:", empty_rpop) # None
输出:
初始列表: ['A', 'B', 'C']
LPOP 弹出: A
LPOP 后列表: ['B', 'C']
RPOP 弹出: C
RPOP 后列表: ['B']
空列表 LPOP: None
空列表 RPOP: None
3.BLPOP示例 (阻塞式队列消费者)
BLPOP 是实现 FIFO(先进先出)队列的标准方式。生产者采用 RPUSH,消费者采用 BLPOP。
# 清理环境
cleanup_keys('task_queue')
def producer():
"""模拟生产者,每隔2秒推送一个任务"""
for i in range(3):
task = f"Task-{i+1}"
r.rpush('task_queue', task)
print(f"[生产者] 推送任务: {task}")
time.sleep(2)
def blpop_consumer():
"""BLPOP 消费者,阻塞等待任务"""
print("[BLPOP消费者] 开始等待任务...")
while True:
# 阻塞等待,超时时间设为5秒
result = r.blpop('task_queue', timeout=5)
if result is None:
print("[BLPOP消费者] 超时,没有收到新任务,退出。")
break
key, value = result
print(f"[BLPOP消费者] 处理任务: {value} (来自 {key})")
# 启动生产者线程
producer_thread = threading.Thread(target=producer)
producer_thread.start()
# 运行消费者
blpop_consumer()
# 等待生产者线程结束
producer_thread.join()
输出:
[BLPOP消费者] 开始等待任务...[生产者] 推送任务: Task-1
[BLPOP消费者] 处理任务: Task-1 (来自 task_queue)
[生产者] 推送任务: Task-2
[BLPOP消费者] 处理任务: Task-2 (来自 task_queue)
[生产者] 推送任务: Task-3[BLPOP消费者] 处理任务: Task-3 (来自 task_queue)
[BLPOP消费者] 超时,没有收到新任务,退出。
4.BRPOP示例 (阻塞式栈或反向队列)
BRPOP 通常与 LPUSH 配合,也能够完成 FIFO 队列,但更常用来实现 LIFO(后进先出)的栈。
# 清理环境
cleanup_keys('stack')
def brpop_consumer():
"""BRPOP 消费者,模拟一个栈的弹出操作"""
print("[BRPOP消费者] 开始从栈中弹出元素...")
# 先手动压入一些元素
r.lpush('stack', 'X', 'Y', 'Z') # 栈: ['Z', 'Y', 'X'] (Z 在顶部/尾部)
print("当前栈内容:", r.lrange('stack', 0, -1))
# 弹出3次
for _ in range(3):
result = r.brpop('stack', timeout=1)
if result:
key, value = result
print(f"[BRPOP消费者] 弹出: {value}")
# 尝试在空栈上弹出,会超时
result = r.brpop('stack', timeout=2)
print("[BRPOP消费者] 空栈弹出结果:", result) # None
brpop_consumer()
输出:
[BRPOP消费者] 开始从栈中弹出元素...
当前栈内容: ['Z', 'Y', 'X']
[BRPOP消费者] 弹出: X
[BRPOP消费者] 弹出: Y
[BRPOP消费者] 弹出: Z
[BRPOP消费者] 空栈弹出结果: None
5.BLPOP/BRPOP多个列表 (优先级队列)
这是阻塞命令的一个强大特性,能够用来实现轻松的优先级队列。
# 清理环境
cleanup_keys('high_priority', 'low_priority')
def multi_list_producer():
"""向高优先级和低优先级队列推送任务"""
time.sleep(1) # 稍等一下,让消费者先启动
r.rpush('low_priority', 'Low-Priority-Task')
print("[生产者] 推送低优先级任务")
time.sleep(1)
r.rpush('high_priority', 'High-Priority-Task')
print("[生产者] 推送高优先级任务")
def priority_consumer():
"""消费者优先高优先级队列"""
print("[优先级消费者] 启动,优先: high_priority, low_priority")
# BLPOP 会按顺序检查列表
for _ in range(2):
result = r.blpop(['high_priority', 'low_priority'], timeout=5)
if result:
key, value = result
print(f"[优先级消费者] 处理任务: {value} (来自 {key})")
# 启动生产者线程
prod_thread = threading.Thread(target=multi_list_producer)
prod_thread.start()
# 运行消费者
priority_consumer()
prod_thread.join()
输出:
[优先级消费者] 启动,优先: high_priority, low_priority
[生产者] 推送低优先级任务
[优先级消费者] 处理任务: Low-Priority-Task (来自 low_priority)
[生产者] 推送高优先级任务
[优先级消费者] 处理任务: High-Priority-Task (来自 high_priority)
总结对比表
| 命令 | 功能 | 弹出方向 | 阻塞 | 典型用途 |
|---|---|---|---|---|
RPOP | 移除并得到最后一个元素 | 尾部 (Right) | 否 | 栈 (LIFO) |
BRPOP | 阻塞式移除并得到最后一个元素 | 尾部 (Right) | 是 | 消费者(配合 LPUSH 实现 FIFO) |
LPOP | 移除并得到第一个元素 | 头部 (Left) | 否 | 栈 (LIFO) (另一端) |
BLPOP | 阻塞式移除并得到第一个元素 | 头部 (Left) | 是 | 标准队列消费者 (FIFO) (配合 RPUSH) |
关键记忆点:
- L 开头的命令操作头部。
- R 开头的命令操作尾部。
- B 开头的命令是阻塞版本。
- 标准 FIFO 队列 = RPUSH (生产者) + BLPOP (消费者)。
在这个场景下,总的来说,redis lpop rpop适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。
-
-
下载
- |
-
-
下载
- 《行尸走肉第一章》免安装中文汉化硬盘版下载
- 单机|436 MB
- 一款以动作冒险为主题的游戏
-
-
下载
- 《街头霸王X铁拳》免安装中文汉化硬盘版下载
- 单机|111MB
- 一款非常好玩的格斗游戏
-
-
下载
- |
-
-
下载
- 《暗黑破坏神3》免安装繁体中文正式版下载
- 单机|7630 MB
- 一款以角色扮演为主题的游戏
-
-
下载
- 《马克思佩恩3》免安装硬盘版下载
- 单机|27033 MB
- 一款以第三人称射击为主题的游戏