当前位置: 首页 > news >正文

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. RPOPLPOP 示例 (非阻塞)

这两个命令会立即返回结果,无论列表是否为空。

# 清理环境
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消费者] 超时,没有收到新任务,退出。")breakkey, value = resultprint(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 = resultprint(f"[BRPOP消费者] 弹出: {value}")# 尝试在空栈上弹出,会超时result = r.brpop('stack', timeout=2)print("[BRPOP消费者] 空栈弹出结果:", result)  # Nonebrpop_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 = resultprint(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 (消费者)
http://www.dtcms.com/a/469223.html

相关文章:

  • R语言学习
  • 【C++】C++11 新特性详解(下)
  • 成都市公园城市建设管理局网站济南百度推广开户
  • 网站的技术建设公司网站建设 wordpress
  • 联想小新平板Pro GT/Y700四代平板无需解锁BL获取root权限方法
  • Linux系统安装PGSQL实现向量存储
  • 跨语言协作新范式:阿里云Qwen-MT与DooTask的翻译技术突破
  • LLM 笔记 —— 04 为什么语言模型用文字接龙,图片模型不用像素接龙呢?
  • ubuntu-20.04.6升级OpenSSH_10.2p1
  • redis lua脚本(go)调用教程以及debug调试
  • shopnc本地生活o2o网站源码有声小说网站开发
  • OpenHarmony 之Telephony电话服务技术详解:架构设计与Modem厂商库集成机制
  • 医疗AI记忆系统的分层存储机制:长期病史与短期会诊记忆的编程实现(代码部分)
  • Vue 基础认知全解析:从版本演进到生态定位
  • 苏州建网站的公司平台收费标准wordpress客户端源码分析
  • VibeCut - 智能剪辑探索与实现
  • Linux5:Linux网络编程
  • 大模型为什么会表现出逻辑性推理
  • 除了MySQL连接命令,实现自动化备份还需哪些步骤?
  • 【GD32】硬件I2C
  • 光学影像“精准导航”交叉导轨的关键作用
  • 四川省城乡住房和城乡建设厅网站注册个人订阅号
  • Linux 进程通信——基于建造者模式的信号量
  • 在Mac上安装CocoaPods问题处理
  • 深入 Spring 条件化配置底层:从硬编码到通用注解的实现原理
  • SpringBoot之配置文件
  • Linux中kmalloc内存分配函数的实现
  • 【Spring Security】Spring Security 概念
  • 杂记 12
  • 织梦程序如何搭建网站洛阳凯锦腾网业有限公司