一、簡介

列表List相當於 數組 或順序表。

列表中的每個字符串稱為元素(element),⼀個列表最多可以存儲 個元素。在 Redis 中,可以對列表兩端插⼊(push)和彈出(pop),還可以獲取指定範圍的元素列表、獲取指定索引下標的元素等。

特點:

  1. 列表中的元素是有序的(列表中元素順序發生改變,就是一個新列表了),這意味着可以通過索引下標獲取某個元素或者某個範圍的元素列表。
  2. 、列表中的元素是允許重複的。
  3. 列表中元素從左到右下標 0 到 n-1 ,也可以從右到左 -1 到 -n 作為元素下標。

二、相關命令

2.1 lpush 和 lrange

lpush將⼀個或者多個元素從左側放⼊(頭插)到 List 中。

語法: lpush key element [element ...]

時間複雜度:只插⼊⼀個元素為 O(1), 插⼊多個元素為 O(N), N 為插⼊元素個數. 返回值:插⼊後 List 的⻓度。

lrange獲取從 start 到 stop 區間的所有元素,左閉右閉,越界的下標不返回元素。

語法:lrange key start stop

時間複雜度:O(N) 返回值:指定區間的元素。

2.2 lpushx

lpushx在 key 存在時,將⼀個或者多個元素從左側放⼊(頭插)到 List 中。不存在,直接返回

語法: lpushx key element [element ...]

命令有效版本:2.0.0之後

時間複雜度:只插⼊⼀個元素為 O(1), 插⼊多個元素為 O(N), N 為插⼊元素個數. 返回值:插⼊後 list 的⻓度。

2.3 rpush 和 rpushx

rpush 將⼀個或者多個元素從右側放⼊(尾插)到 list 中。

語法: rpush key element [element ...]

時間複雜度:只插⼊⼀個元素為 O(1), 插⼊多個元素為 O(N), N 為插⼊元素個數. 返回值:插⼊後 list 的⻓度。

rpushx在 key 存在時,將⼀個或者多個元素從左側放⼊(頭插)到 List 中。不存在,直接返回

語法: rpushxkey element [element ...]

命令有效版本:2.0.0之後

時間複雜度:只插⼊⼀個元素為 O(1), 插⼊多個元素為 O(N), N 為插⼊元素個數. 返回值:插⼊後 list 的⻓度。

2.4 lpop 和 rpop

lpop從 list 左側取出元素(即頭刪)。

語法: lpop key [count]

時間複雜度:O(1) 返回值:取出的元素或者 nil。

rpop從 list 右側取出元素(即尾刪)。

語法: rpop key [count]

時間複雜度:O(1)

返回值:取出的元素或者 nil。

從Redis 6.2 後的版本,才新增了一個count參數。描述這次頭/尾刪,刪幾個元素。

2.5 lindex 和 linsert

lindex獲取從左數第 index 位置的元素。

語法: lindex key index

時間複雜度:O(N) 返回值:取出的元素或者 nil。

linsert在特定位置插⼊元素。

語法: linsert key <BEFORE | AFTER> pivot element

  • before: 插在 pivot 左邊
  • after: 插在 pivot 右邊
  • pivot :元素值,從左往右找到的第一個

命令有效版本:2.2.2 之後

時間複雜度:O(N) 返回值:插⼊後的 list ⻓度。

2.6 llen

llen 獲取 list ⻓度。

語法: llen key

時間複雜度:O(1) 返回值:list 的⻓度。

2.7 lrem

lrem 刪除一個或多個元素

語法: lrem key count element

  • count : 要刪除的元素個數,count大於0,從左往右找刪除count個;count小於0,從右往左找刪除-count個;count為0,刪除所有element元素。
  • element:要刪除的元素值

時間複雜度:O(N+M) , N是列表List長度,M是要刪除的個數。 返回值:成功刪除的元素個數。

2.8 ltrim 和 lset

ltrim 保留區間 start 和 stop 區間(左閉右閉)的元素,其餘元素全部刪除。

語法: ltrim key start stop

時間複雜度:O(N) , N是保留元素個數。 返回值:OK

lset 根據下標修改元素

語法 lset key index element

時間複雜度:O(N) 返回值:成功修改OK,下標越界報錯(error) ERR index out of range

2.9 blpop 和 brpop

blpop 和 brpop 是 lpop 和 rpop 的阻塞版本,和對應⾮阻塞版本的作⽤基本⼀致,除了:

  • 在列表中有元素的情況下,阻塞和⾮阻塞表現是⼀致的。但如果列表中沒有元素,⾮阻塞版本會理解返回 nil,但阻塞版本會根據 timeout,阻塞⼀段時間(可以設置等待時間 ),期間 Redis 可以執⾏其他命令(阻塞期間不會對Redis使用產生影響),但要求執⾏該命令的客⼾端會表現為阻塞狀態。
  • 命令中如果設置了多個鍵,那麼會從左向右進⾏遍歷鍵,⼀旦有⼀個鍵對應的列表中可以彈出元素,命令⽴即返回。
  • 如果多個客⼾端同時多⼀個鍵執⾏ pop,則最先執⾏命令的客⼾端會得到彈出的元素。

blpop lpop 頭刪 的阻塞版本。

語法:blpop key [key ...] timeout

時間複雜度:O(1)返回值:取出的元素或者 nil。

brpop rpop 尾刪 的阻塞版本。

語法:brpop key [key ...] timeout

時間複雜度:O(1)返回值:取出的元素或者 nil。

2.10 小結

操作類型

命令

執行效果

時間複雜度

添加

rpush key value [value ...]

尾插一個或多個元素

O(k),k 是元素個數

添加

lpush key value [value ...]

頭插一個或多個元素

O(k),k 是元素個數

添加

linsert key <before / after> pivot value

在特定位置 pivot元素 左邊或右邊 插⼊元素

O(n),n 是 pivot 距離頭尾的距離

查找

lrange key start end

獲取從 start 到 end 區間的所有元素,左閉右閉,越界的下標不返回元素

O(s+n),s 是 start 偏移量,n 是 start 到 end 的範圍

查找

lindex key index

獲取從左數第 index 位置的元素

O(n),n 是索引的偏移量

查找

llen key

獲取 list ⻓度

O(1)

刪除

lpop key

頭刪一個元素

O(1)

刪除

rpop key

尾刪一個元素

O(1)

刪除

lremkey count value

刪除一個或多個元素

O(k),k 是元素個數

刪除

ltrim key start end

保留區間 start 和 stop 區間(左閉右閉)的元素,其餘元素全部刪除

O(k),k 是元素個數

修改

lset key index value

根據下標修改元素

O(n),n 是索引的偏移量

阻塞操作

blpop brpop


O(1)

三、內部編碼

Redis3.2之前,列表類型的內部編碼有兩種:

  • ziplist(壓縮列表):當列表的元素個數⼩於 list-max-ziplist-entries 配置(默認 512 個),同時列表中每個元素的⻓度都⼩於 list-max-ziplist-value 配置(默認 64 字節)時,Redis 會選⽤ ziplist 來作為列表的內部編碼實現來減少內存消耗。
  • linkedlist(鏈表):當列表類型⽆法滿⾜ ziplist 的條件時,Redis 會使⽤ linkedlist 作為列表的內部實現。

在Redis3.2之後,使用quicklist代替上面兩種。quicklist就是一個元素是ziplist的鏈表,使用 list-max-ziplist-size 配置每個壓縮列表的大小。

四、應用場景

4.1 消息隊列

Redis 可以使⽤ lpush + brpop 命令組合實現經典的阻塞式⽣產者-消費者模型隊列,⽣產者客⼾端使⽤ lpush 從列表側插⼊元素,多個消費者客⼾端使⽤ brpop 命令阻塞式地從隊列中"爭搶" 隊⾸元素。通過多個客⼾端來保證消費的負載均衡和⾼可⽤性。

4.2 分頻道的消息隊列

Redis 同樣使⽤ lpush + brpop 命令,但通過不同的鍵模擬頻道的概念,不同的消費者可以通過 brpop 不同的鍵值,實現訂閲不同頻道的理念。