2.4 列表 List
List 是一个有序、可重复的字符串列表,两端都能插入和弹出。用它可以做队列、栈、"最新 N 条"列表。
1. List 是什么
想象一根两端开口的管子,元素按插入顺序排列:
左边(L) ←→ [ a, b, c, d ] ←→ 右边(R)
- 有序:按你插入的顺序保存(不是按大小排序)
- 可重复:同一个值可以出现多次
- 两端都可以 push(塞入)和 pop(弹出),所以能同时模拟队列和栈
2. 基础操作
List 命令以 l(left / list)或 r(right)开头:
# 从左边压入(注意:多个元素时是逐个从左塞入)
127.0.0.1:6379> lpush mylist a b c
(integer) 3
# 过程:[a] → [b,a] → [c,b,a],所以现在列表是 c,b,a
# 从右边压入
127.0.0.1:6379> rpush mylist x
(integer) 4
# 现在是 [c, b, a, x]
# 查看范围(0 是第一个,-1 是最后一个,lrange key 0 -1 = 查看全部)
127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "b"
3) "a"
4) "x"
# 从左弹出 / 从右弹出(取出并删除)
127.0.0.1:6379> lpop mylist
"c"
127.0.0.1:6379> rpop mylist
"x"
# 长度
127.0.0.1:6379> llen mylist
(integer) 2
# 按下标取单个元素(不删除)
127.0.0.1:6379> lindex mylist 0
"b"
💡 记忆技巧:
lrange的下标支持负数,-1是最后一个、-2是倒数第二个,和 Python 切片一样。
3. 用 List 实现队列和栈
这是理解 List 的关键,就两个公式:
队列(先进先出 FIFO):lpush + rpop (左边进,右边出)
栈 (后进先出 LIFO):lpush + lpop (左边进,左边出)
动手体验队列:
127.0.0.1:6379> lpush queue 任务1
(integer) 1
127.0.0.1:6379> lpush queue 任务2
(integer) 2
127.0.0.1:6379> rpop queue
"任务1" # 先进来的先出去 ✓
127.0.0.1:6379> rpop queue
"任务2"
4. 阻塞弹出:BLPOP / BRPOP
做消息队列时有个问题:消费者怎么知道队列里有没有新任务?总不能写死循环不停地 rpop 吧(这叫轮询,浪费资源)。
Redis 提供了阻塞版的 pop:队列为空时,连接会原地等待,直到有新元素进来或超时:
# 等待 queue 出现元素,最多等 30 秒(0 表示无限等待)
127.0.0.1:6379> brpop queue 30
(此处会卡住...直到另一个客户端 lpush queue 新任务)
1) "queue"
2) "新任务"
可以开两个 redis-cli 窗口试试:一个执行 brpop queue 0 等着,另一个 lpush queue hello,观察第一个窗口立刻收到数据。这就是一个最简单的生产者-消费者模型。
5. 其他实用命令
# 只保留指定范围,其余删除(做"最新 N 条"的关键)
127.0.0.1:6379> ltrim mylist 0 99 # 只留前 100 个
# 删除值等于 x 的元素:count>0 从左删 count 个,<0 从右删,=0 删所有
127.0.0.1:6379> lrem mylist 1 "b"
# 修改指定下标的值
127.0.0.1:6379> lset mylist 0 "newvalue"
6. 典型应用场景
场景一:最新动态列表(朋友圈 / 微博时间线)
新内容从左边进,永远只保留最新 100 条:
lpush user:1001:feed "动态ID:9527"
ltrim user:1001:feed 0 99 # 修剪,防止无限增长
lrange user:1001:feed 0 9 # 取最新 10 条展示
场景二:简易任务队列
# 生产者(Web 服务):用户下单后把任务扔进队列
lpush task:send_email '{"to":"a@b.com","subject":"订单确认"}'
# 消费者(后台进程):阻塞式取任务处理
brpop task:send_email 0
💡 List 做队列简单好用,但没有 ack 确认机制——消费者取走任务后如果崩溃了,任务就丢了。对可靠性要求高的场景用 Redis Stream 或专业消息队列(RabbitMQ/Kafka)。
7. 动手练习
- 用
lpush+ltrim+lrange模拟"浏览历史":依次浏览商品 101~105,只保留最近 3 条,查看结果应为 105、104、103 - 开两个终端窗口,体验
brpop的阻塞效果 - 思考:
rpush + lpop也是队列吗?(是的,方向反过来而已)
8. 小结
| 命令 | 作用 |
|---|---|
lpush / rpush | 左 / 右压入 |
lpop / rpop | 左 / 右弹出 |
blpop / brpop | 阻塞式弹出(做队列用) |
lrange key 0 -1 | 查看全部元素 |
ltrim | 只保留指定范围 |
llen / lindex / lrem | 长度 / 按下标取 / 删除指定值 |
记住两个公式:lpush + rpop = 队列,lpush + lpop = 栈。
下一章:天生去重的集合 👉 2.5 集合 Set