Redis List 是一种基于双向链表的有序数据结构,插入和删除时间复杂度为 O(1),但按索引查询为 O(n)。本文从底层 quicklist 与 ziplist 的存储原理切入,结合常用命令演示与队列/栈实现示例,帮助开发者掌握 List 的核心用法与适用场景。
底层存储:quicklist 与 ziplist 的协同机制
Redis List 的底层并非传统单向或双向链表,而是采用 quicklist(快速链表) 结构。该结构根据数据量动态切换存储策略:
- 数据量较小时:使用 ziplist(压缩列表)。ziplist 是一块连续内存,通过特殊编码将多个节点紧密排列,每个节点可保存字符数组或整数值,显著降低内存碎片与开销。
- 数据量较大时:切换为 quicklist。Redis 将多个 ziplist 通过双向指针串联,既保留了链表 O(1) 插入/删除的优势,又避免了纯链表带来的指针空间浪费。
当列表弹出最后一个元素时,该 List 结构会被自动删除。单个 List 最多可容纳 2^32 - 1 个元素(约 40 亿)。

图1:快速链表结构示意图
核心命令演示与交互示例
List 操作围绕“左(头部)/右(尾部)”展开。以下示例展示元素的插入、范围查询、指定位置插入与弹出:
# 从左侧头部插入元素 127.0.0.1:6379> LPUSH www.biancheng.net python (integer) 1 127.0.0.1:6379> LPUSH www.biancheng.net java c c# (integer) 4 # 查看插入的元素 127.0.0.1:6379> LRANGE www.biancheng.net 0 4 1) "c#" 2) "c" 3) "java" 4) "python" # 从右侧尾部插入元素 127.0.0.1:6379> RPUSH www.biancheng.net "Math" (integer) 5 127.0.0.1:6379> RPUSH www.biancheng.net "Computer Language" (integer) 6 # 查看元素 127.0.0.1:6379> LRANGE www.biancheng.net 0 6 1) "c#" 2) "c" 3) "java" 4) "python" 5) "Math" 6) "Computer Language" # 在 python 前面插入元素 127.0.0.1:6379> LINSERT www.biancheng.net BEFORE python Python (integer) 7 # 从左侧弹出元素 127.0.0.1:6379> LPOP www.biancheng.net "c#" # 从右侧弹出元素 127.0.0.1:6379> RPOP www.biancheng.net "Computer Language"
用 List 实现队列、栈与异步任务调度
凭借两端操作能力,Redis List 可轻松模拟常见数据结构:
队列模型(左进右出 / 右进左出)
以“右进左出”为例,符合先进先出(FIFO)特性:
127.0.0.1:6379> RPUSH book c python java (integer) 3 127.0.0.1:6379> LPOP book "c" 127.0.0.1:6379> LPOP book "python" 127.0.0.1:6379> LPOP book "java" 127.0.0.1:6379> LPOP book (nil)
栈模型(右进右出 / 左进左出)
以“右进右出”为例,符合后进先出(LIFO)特性:
127.0.0.1:6379> RPUSH book c python java (integer) 3 127.0.0.1:6379> RPOP book "java" 127.0.0.1:6379> RPOP book "python" 127.0.0.1:6379> RPOP book "c" 127.0.0.1:6379> RPOP book (nil)
异步队列实践
List 常被用于轻量级异步任务调度:生产者线程将任务序列化为字符串后通过 RPUSH 推入列表,消费者线程通过 LPOP 或阻塞命令轮询拉取并执行。该模式实现简单,但需注意空列表轮询带来的 CPU 开销,建议在生产环境使用 BLPOP/BRPOP 等阻塞命令替代忙等待。
常用命令速查表
| 命令 | 说明 |
|---|---|
LPUSH key value1 [value2] | 在列表头部插入一个或多个值。 |
LRANGE key start stop | 获取列表指定范围内的元素。 |
RPUSH key value1 [value2] | 在列表尾部添加一个或多个值。 |
LPUSHX key value | 仅当 key 存在时,将值插入列表头部。 |
RPUSHX key value | 仅当 key 存在时,将值插入列表尾部。 |
LINDEX key index | 通过索引获取列表中的元素。 |
LINSERT key before|after pivot value | 在指定元素之前或之后插入新元素。 |
LREM key count value | 删除与 value 相等的元素;count 为 0 表示全部移除。 |
LSET key index value | 通过索引设置列表中元素的值。 |
LTRIM key start stop | 仅保留指定范围内的元素,其余删除。 |
LPOP key | 从列表头部弹出并返回第一个元素。 |
RPOP key | 从列表尾部弹出并返回最后一个元素。 |
LLEN key | 获取列表当前长度。 |
RPOPLPUSH source destination | 弹出 source 尾部元素并插入 destination 头部,返回该元素。 |
BLPOP key1 [key2] timeout | 阻塞式弹出头部元素;列表为空时阻塞,直到超时或出现可弹出元素。 |
BRPOP key1 [key2] timeout | 阻塞式弹出尾部元素;行为同 BLPOP。 |
BRPOPLPUSH source destination timeout | 阻塞式弹出 source 尾部元素并推入 destination 头部。 |
