list 是一個鏈表結構,主要功能是 push、pop、獲取一個范圍的所有值等等,操作中 key理解為鏈表的名字。
Redis 的 list類型其實就是一個每個子元素都是 string 類型的雙向鏈表。鏈表的最大長度是(2的 32 次方)。我們可以通過 push,pop 操作從鏈表的頭部或者尾部添加刪除元素。這使得 list既可以用作棧,也可以用作隊列。
有意思的是 list 的 pop 操作還有阻塞版本的,當我們[lr]pop 一個 list 對象時,如果 list 是空,或者不存在,會立即返回 nil。但是阻塞版本的 b[lr]pop 可以則可以阻塞,當然可以加超時時間,超時後也會返回 nil。為什麼要阻塞版本的 pop 呢,主要是為了避免輪詢。舉個簡單的例子如果我們用 list 來實現一個工作隊列。 執行任務的 thread 可以調用阻塞版本的 pop 去獲取任務這樣就可以避免輪詢去檢查是否有任務存在。當任務來時候工作線程可以立即返回,也可以避免輪詢帶來的延遲。
Redis list應用場景非常多,也是Redis最重要的數據結構之一,比如微博的關注列表,粉絲列表等都可以用Redis的list結構來實現;博客實現中,可為每篇日志設置一個list,在該list中推入進博客評論;也可以使用Redis list實現消息隊列。
list中的數據邏輯上存在順序關系(數組的下表),適合存儲帶有順序特性(空間、時間屬性)的數據。比如,記錄用戶在網站上浏覽商品id,這種帶時間屬性的數據可以用來分析用戶的購物行為。
list作為queue,一端加入數據,另一端讀取數據,最典型的就是生產者/消費者模型,比如:商品秒殺,從已經初始化隊列中pop出數據,直到隊列為空。
list作為stack,只操作list的一端,數據先進後出。
LPUSH
LPUSH key value [value …]
將一個或多個值 value 插入到列表 key 的表頭如果有多個 value 值,那麼各個 value 值按從左到右的順序依次插入到表頭:比如說,對空列表 mylist執行命令 LPUSH mylist a b c ,列表的值將是 c b a ,這等同於原子性地執行 LPUSH mylist a 、LPUSH mylist b 和 LPUSH mylist c 三個命令。
如果 key 不存在,一個空列表會被創建並執行LPUSH 操作。
當 key 存在但不是列表類型時,返回一個錯誤。
時間復雜度: O(1)
返回值: 執行LPUSH 命令後,列表的長度。
127.0.0.1:6379[15]> LPUSH languages python
(integer) 1
127.0.0.1:6379[15]> LPUSH languages python
(integer) 2
127.0.0.1:6379[15]> LRANGE languages 0 -1
1) "python"
2) "python"
127.0.0.1:6379[15]> LPUSH mylist a b c
(integer) 3
127.0.0.1:6379[15]> LRANGE mylist 0 -1
1) "c"
2) "b"
3) "a"
LPUSHX
LPUSHX key value
將值 value 插入到列表 key 的表頭,當且僅當 key 存在並且是一個列表。
和LPUSH 命令相反,當 key 不存在時,LPUSHX 命令什麼也不做。
時間復雜度: O(1)
返回值: LPUSHX 命令執行之後,表的長度。
127.0.0.1:6379[15]> LLEN greet
(integer) 0
127.0.0.1:6379[15]> LPUSHX greet "hello"
(integer) 0
127.0.0.1:6379[15]> LPUSH greet "hello"
(integer) 1
127.0.0.1:6379[15]> LPUSHX greet "good morning"
(integer) 2
127.0.0.1:6379[15]> LRANGE greet 0 -1
1) "good morning"
2) "hello"
RPUSH
RPUSH key value [value …]
將一個或多個值 value 插入到列表 key 的表尾 (最右邊)。
如果有多個 value 值,那麼各個 value 值按從左到右的順序依次插入到表尾:比如對一個空列表 mylist執行 RPUSH mylist a b c ,得出的結果列表為 a b c ,等同於執行命令 RPUSH mylist a 、RPUSH mylist b 、RPUSH mylist c 。
如果 key 不存在,一個空列表會被創建並執行RPUSH 操作。
當 key 存在但不是列表類型時,返回一個錯誤。
時間復雜度: O(1)
返回值: 執行RPUSH 操作後,表的長度。
127.0.0.1:6379[15]> RPUSH languages c
(integer) 1
127.0.0.1:6379[15]> RPUSH languages c
(integer) 2
127.0.0.1:6379[15]> LRANGE languages 0 -1
1) "c"
2) "c"
127.0.0.1:6379[15]> RPUSH mylist a b c
(integer) 3
127.0.0.1:6379[15]> LRANGE mylist 0 -1
1) "a"
2) "b"
3) "c"
RPUSHX
RPUSHX key value
將值 value 插入到列表 key 的表尾,當且僅當 key 存在並且是一個列表。
和RPUSH 命令相反,當 key 不存在時,RPUSHX 命令什麼也不做。
時間復雜度: O(1)
返回值: RPUSHX 命令執行之後,表的長度。
127.0.0.1:6379[15]> LLEN greet
(integer) 0
127.0.0.1:6379[15]> LPUSHX greet "hello"
(integer) 0
127.0.0.1:6379[15]> LPUSH greet "hello"
(integer) 1
127.0.0.1:6379[15]> LPUSHX greet "good morning"
(integer) 2
127.0.0.1:6379[15]> LRANGE greet 0 -1
1) "good morning"
2) "hello"
LPOP
LPOP key
移除並返回列表 key 的頭元素。
時間復雜度: O(1)
返回值:
列表的頭元素。
當 key 不存在時,返回 nil 。
127.0.0.1:6379[15]> LLEN course
(integer) 0
127.0.0.1:6379[15]> RPUSH course algorithm001
(integer) 1
127.0.0.1:6379[15]> RPUSH course c++101
(integer) 2
127.0.0.1:6379[15]> LPOP course
"algorithm001"
RPOP
RPOP key
移除並返回列表 key 的尾元素。
時間復雜度: O(1)
返回值:
列表的尾元素。
當 key 不存在時,返回 nil 。
127.0.0.1:6379[15]> RPUSH mylist "one"
(integer) 1
127.0.0.1:6379[15]> RPUSH mylist "two"
(integer) 2
127.0.0.1:6379[15]> RPUSH mylist "three"
(integer) 3
127.0.0.1:6379[15]> RPOP mylist
"three"
127.0.0.1:6379[15]> LRANGE mylist 0 -1
1) "one"
2) "two"
BLPOP
BLPOP key [key …] timeout
BLPOP 是列表的阻塞式 (blocking) 彈出原語。
它是LPOP 命令的阻塞版本,當給定列表內沒有任何元素可供彈出的時候,連接將被BLPOP 命令阻塞,直到等待超時或發現可彈出元素為止。
當給定多個 key 參數時,按參數 key 的先後順序依次檢查各個列表,彈出第一個非空列表的頭元素。非阻塞行為當BLPOP 被調用時,如果給定 key 內至少有一個非空列表,那麼彈出遇到的第一個非空列表的頭元素,並和被彈出元素所屬的列表的名字一起,組成結果返回給調用者。
當存在多個給定 key 時,BLPOP 按給定 key 參數排列的先後順序,依次檢查各個列表。
假設現在有 job 、command 和 request 三個列表,其中 job 不存在,command 和 request 都持有非空列表。考慮以下命令:
BLPOP job command request 0
BLPOP 保證返回的元素來自 command,因為它是按” 查找 job -> 查找 command -> 查找 request “這樣的順序,第一個找到的非空列表。
127.0.0.1:6379[15]> DEL job command request
(integer) 0
127.0.0.1:6379[15]> LPUSH command "update system..."
(integer) 1
127.0.0.1:6379[15]> LPUSH request "visit page"
(integer) 1
127.0.0.1:6379[15]> BLPOP job command request 0
1) "command"
2) "update system..."
BRPOP
BRPOP key [key …] timeout
BRPOP 是列表的阻塞式 (blocking) 彈出原語。
它是RPOP 命令的阻塞版本,當給定列表內沒有任何元素可供彈出的時候,連接將被BRPOP 命令阻塞,直 到等待超時或發現可彈出元素為止。
當給定多個 key 參數時,按參數 key 的先後順序依次檢查各個列表,彈出第一個非空列表的尾部元素。
關於阻塞操作的更多信息,請查看BLPOP 命令,BRPOP 除了彈出元素的位置和BLPOP 不同之外,其他表現一致。
時間復雜度: O(1)
返回值:
假如在指定時間內沒有任何元素被彈出,則返回一個 nil 和等待時長。
反之,返回一個含有兩個元素的列表,第一個元素是被彈出元素所屬的 key ,第二個元素是被彈出元素的值。
127.0.0.1:6379[15]> LLEN course
(integer) 0
127.0.0.1:6379[15]> RPUSH course algorithm001
(integer) 1
127.0.0.1:6379[15]> RPUSH course c++101
(integer) 2
127.0.0.1:6379[15]> BRPOP course 30
1) "course"
2) "c++101"
LINSERT
LINSERT key BEFORE|AFTER pivot value
將值 value 插入到列表 key 當中,位於值 pivot 之前或之後。
當 pivot 不存在於列表 key 時,不執行任何操作。
當 key 不存在時,key 被視為空列表,不執行任何操作。
如果 key 不是列表類型,返回一個錯誤。
時間復雜度: O(N),N 為尋找 pivot 過程中經過的元素數量。
返回值:
如果命令執行成功,返回插入操作完成之後,列表的長度。
如果沒有找到 pivot ,返回 -1 。
如果 key 不存在或為空列表,返回 0 。
127.0.0.1:6379[15]> RPUSH mylist "Hello"
(integer) 1
127.0.0.1:6379[15]> RPUSH mylist "World"
(integer) 2
127.0.0.1:6379[15]> LINSERT mylist BEFORE "World" "There"
(integer) 3
127.0.0.1:6379[15]> LRANGE mylist 0 -1
1) "Hello"
2) "There"
3) "World"
127.0.0.1:6379[15]> LINSERT mylist BEFORE "go" "let's"
(integer) -1
127.0.0.1:6379[15]> EXISTS fake_list
(integer) 0
127.0.0.1:6379[15]> LINSERT fake_list BEFORE "nono" "gogogog"
(integer) 0
LRANGE
LRANGE key start stop
返回列表 key 中指定區間內的元素,區間以偏移量 start 和 stop 指定。
下標 (index) 參數 start 和 stop 都以 0 為底,也就是說,以 0 表示列表的第一個元素,以 1 表示列表的第二個元素,以此類推。
你也可以使用負數下標,以 -1 表示列表的最後一個元素,-2 表示列表的倒數第二個元素,以此類推。
注意 LRANGE 命令和編程語言區間函數的區別假如你有一個包含一百個元素的列表,對該列表執行 LRANGE list 0 10 ,結果是一個包含 11 個元素的列表,這表明 stop下標也在LRANGE命令的取值范圍之內 (閉區間),這和某些語言的區間函數可能不一致,比如 Ruby 的 Range.new 、Array#slice 和 Python 的 range() 函數。
超出范圍的下標值不會引起錯誤。
如果 start 下標比列表的最大下標 end ( LLEN list 減去 1 ) 還要大,那麼LRANGE 返回一個空列表。
如果 stop 下標比 end 下標還要大,Redis 將 stop 的值設置為 end 。
時間復雜度: O(S+N),S 為偏移量 start ,N 為指定區間內元素的數量。
返回值: 一個列表,包含指定區間內的元素。
127.0.0.1:6379[15]> RPUSH fp-language lisp
(integer) 1
127.0.0.1:6379[15]> LRANGE fp-language 0 0
1) "lisp"
127.0.0.1:6379[15]> RPUSH fp-language scheme
(integer) 2
127.0.0.1:6379[15]> LRANGE fp-language 0 1
1) "lisp"
2) "scheme"
LREM
LREM key count value
根據參數 count 的值,移除列表中與參數 value 相等的元素。
count 的值可以是以下幾種:
count > 0 : 從表頭開始向表尾搜索,移除與 value 相等的元素,數量為 count 。
count < 0 : 從表尾開始向表頭搜索,移除與 value 相等的元素,數量為 count 的絕對值。
count = 0 : 移除表中所有與 value 相等的值。
時間復雜度: O(N),N 為列表的長度。
返回值:
被移除元素的數量。
因為不存在的 key 被視作空表 (empty list),所以當 key 不存在時,LREM 命令總是返回 0 。
127.0.0.1:6379[15]> LPUSH greet "morning"
(integer) 1
127.0.0.1:6379[15]> LPUSH greet "hello"
(integer) 2
127.0.0.1:6379[15]> LPUSH greet "morning"
(integer) 3
127.0.0.1:6379[15]> LPUSH greet "hello"
(integer) 4
127.0.0.1:6379[15]> LPUSH greet "morning"
(integer) 5
127.0.0.1:6379[15]> LRANGE greet 0 4
1) "morning"
2) "hello"
3) "morning"
4) "hello"
5) "morning"
127.0.0.1:6379[15]> LREM greet 2 morning
(integer) 2
127.0.0.1:6379[15]> LLEN greet
(integer) 3
127.0.0.1:6379[15]> LRANGE greet 0 2
1) "hello"
2) "hello"
3) "morning"
127.0.0.1:6379[15]> LREM greet -1 morning
(integer) 1
127.0.0.1:6379[15]> LLEN greet
(integer) 2
127.0.0.1:6379[15]> LRANGE greet 0 1
1) "hello"
2) "hello"
127.0.0.1:6379[15]> LREM greet 0 hello
(integer) 2
127.0.0.1:6379[15]> LLEN greet
(integer) 0
LTRIM
LTRIM key start stop
對一個列表進行修剪 (trim),就是說,讓列表只保留指定區間內的元素,不在指定區間之內的元素都將被刪除。
舉個例子,執行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三個元素,其余元素全部刪除。
下標 (index) 參數 start 和 stop 都以 0 為底,也就是說,以 0 表示列表的第一個元素,以 1 表示列表的第二個元素,以此類推。
你也可以使用負數下標,以 -1 表示列表的最後一個元素,-2 表示列表的倒數第二個元素,以此類推。當 key 不是列表類型時,返回一個錯誤。
LTRIM 命令通常和LPUSH 命令或RPUSH 命令配合使用,舉個例子:
LPUSH log newest_log
LTRIM log 0 99
這個例子模擬了一個日志程序,每次將最新日志 newest_log 放到 log 列表中,並且只保留最新的 100 項。注意當這樣使用 LTRIM 命令時,時間復雜度是 O(1),因為平均情況下,每次只有一個元素被移除。
注意 LTRIM 命令和編程語言區間函數的區別
假如你有一個包含一百個元素的列表 list ,對該列表執行 LTRIM list 0 10 ,結果是一個包含 11 個元素的列表,這表明 stop 下標也在LTRIM 命令的取值范圍之內 (閉區間),這和某些語言的區間函數可能不一致,比如 Ruby 的 Range.new 、Array#slice 和 Python 的 range() 函數。
超出范圍的下標值不會引起錯誤。
如果 start 下標比列表的最大下標 end ( LLEN list 減去 1 ) 還要大,或者 start > stop ,LTRIM 返回一個空列表 (因為LTRIM 已經將整個列表清空)。
如果 stop 下標比 end 下標還要大,Redis 將 stop 的值設置為 end 。
時間復雜度: O(N),N 為被移除的元素的數量。
返回值:命令執行成功時,返回 ok 。
# 情況 1: 常見情況, start 和 stop 都在列表的索引范圍之內
127.0.0.1:6379[15]> LPUSH alpha h e l l o
(integer) 5
127.0.0.1:6379[15]> LRANGE alpha 0 -1
1) "o"
2) "l"
3) "l"
4) "e"
5) "h"
127.0.0.1:6379[15]> LTRIM alpha 1 -1
OK
127.0.0.1:6379[15]> LRANGE alpha 0 -1 # o被刪除了
1) "l"
2) "l"
3) "e"
4) "h"
# 情況 2: stop 比列表的最大下標還要大
127.0.0.1:6379[15]> LTRIM alpha 1 10086
OK
127.0.0.1:6379[15]> LRANGE alpha 0 -1 # 只有索引 0 上的元素 "l" 被刪除了,其他元素還在
1) "l"
2) "e"
3) "h"
127.0.0.1:6379[15]> LTRIM alpha 10086 123321
OK
# 情況 4: start 和 stop 都比列表的最大下標要大,並且 start > stop
127.0.0.1:6379[15]> LRANGE alpha 0 -1
(empty list or set)
127.0.0.1:6379[15]> RPUSH new-alpha "h" "e" "l" "l" "o"
(integer) 5
127.0.0.1:6379[15]> LRANGE new-alpha 0 -1
1) "h"
2) "e"
3) "l"
4) "l"
5) "o"
127.0.0.1:6379[15]> LTRIM new-alpha 123321 10086
OK
127.0.0.1:6379[15]> LRANGE new-alpha 0 -1
(empty list or set)
LSET
LSET key index value
將列表 key 下標為 index 的元素的值設置為 value 。
當 index 參數超出范圍,或對一個空列表 ( key 不存在) 進行LSET 時,返回一個錯誤。
時間復雜度:
對頭元素或尾元素進行LSET 操作,復雜度為 O(1)。
其他情況下,為 O(N),N 為列表的長度。
返回值: 操作成功返回 ok ,否則返回錯誤信息。
127.0.0.1:6379[15]> EXISTS list
(integer) 0
127.0.0.1:6379[15]> LSET list 0 item
(error) ERR no such key
127.0.0.1:6379[15]> LPUSH job "cook food"
(integer) 1
127.0.0.1:6379[15]> LRANGE job 0 0
1) "cook food"
127.0.0.1:6379[15]> LSET job 0 "play game"
OK
127.0.0.1:6379[15]> LRANGE job 0 0
1) "play game"
127.0.0.1:6379[15]> LPUSH list a
(integer) 1
127.0.0.1:6379[15]> llen list
(integer) 1
127.0.0.1:6379[15]> LSET list 3 b
(error) ERR index out of range
LINDEX
LINDEX key index
返回列表 key 中,下標為 index 的元素。
下標 (index) 參數 start 和 stop 都以 0 為底,也就是說,以 0 表示列表的第一個元素,以 1 表示列表的第二個元素,以此類推。
你也可以使用負數下標,以 -1 表示列表的最後一個元素,-2 表示列表的倒數第二個元素,以此類推。如果 key 不是列表類型,返回一個錯誤。
時間復雜度:
O(N),N 為到達下標 index 過程中經過的元素數量。
因此,對列表的頭元素和尾元素執行LINDEX 命令,復雜度為 O(1)。
返回值:
列表中下標為 index 的元素。
如果 index 參數的值不在列表的區間范圍內 (out of range),返回 nil 。
127.0.0.1:6379[15]> LPUSH mylist "World"
(integer) 1
127.0.0.1:6379[15]> LPUSH mylist "Hello"
(integer) 2
127.0.0.1:6379[15]> LINDEX mylist 0
"Hello"
127.0.0.1:6379[15]> LINDEX mylist -1
"World"
127.0.0.1:6379[15]> LINDEX mylist 3
(nil)
LLEN
LLEN key
返回列表 key 的長度。
如果 key 不存在,則 key 被解釋為一個空列表,返回 0 .
如果 key 不是列表類型,返回一個錯誤。
時間復雜度: O(1)
返回值: 列表 key 的長度。
127.0.0.1:6379[15]> LLEN job
(integer) 0
127.0.0.1:6379[15]> LPUSH job "cook food"
(integer) 1
127.0.0.1:6379[15]> LPUSH job "have lunch"
(integer) 2
127.0.0.1:6379[15]> LLEN job
(integer) 2
RPOPLPUSH
RPOPLPUSH source destination
命令RPOPLPUSH 在一個原子時間內,執行以下兩個動作:
將列表 source 中的最後一個元素 (尾元素) 彈出,並返回給客戶端。
將 source 彈出的元素插入到列表 destination ,作為 destination 列表的的頭元素。
舉個例子,你有兩個列表 source 和 destination ,source 列表有元素 a, b, c ,destination 列表有元素 x, y, z ,執行 RPOPLPUSH source destination 之後,source 列表包含元素 a, b ,destination 列表包含元素 c, x, y, z ,並且元素 c 會被返回給客戶端。
如果 source 不存在,值 nil 被返回,並且不執行其他動作。
如果 source 和 destination 相同,則列表中的表尾元素被移動到表頭,並返回該元素,可以把這種特殊情況視作列表的旋轉 (rotation) 操作。
時間復雜度: O(1)
返回值: 被彈出的元素。
127.0.0.1:6379[15]> LPUSH alpha d c b a
(integer) 4
127.0.0.1:6379[15]> LRANGE alpha 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379[15]> RPOPLPUSH alpha reciver
"d"
127.0.0.1:6379[15]> LRANGE alpha 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379[15]> LRANGE reciver 0 -1
1) "d"
127.0.0.1:6379[15]> RPOPLPUSH alpha reciver
"c"
127.0.0.1:6379[15]> LRANGE alpha 0 -1
1) "a"
2) "b"
127.0.0.1:6379[15]> LRANGE reciver 0 -1
1) "c"
2) "d"
source 和 destination 相同
127.0.0.1:6379[15]> RPUSH number 1 2 3 4
(integer) 4
127.0.0.1:6379[15]> LRANGE number 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379[15]> RPOPLPUSH number number
"4"
127.0.0.1:6379[15]> LRANGE number 0 -1
1) "4"
2) "1"
3) "2"
4) "3"
127.0.0.1:6379[15]> RPOPLPUSH number number
"3"
127.0.0.1:6379[15]> LRANGE number 0 -1
1) "3"
2) "4"
3) "1"
4) "2"
BRPOPLPUSH
BRPOPLPUSH source destination timeout
BRPOPLPUSH 是RPOPLPUSH 的阻塞版本,當給定列表 source 不為空時,BRPOPLPUSH 的表現和RPOPLPUSH 一樣。
當列表 source 為空時,BRPOPLPUSH 命令將阻塞連接,直到等待超時,或有另一個客戶端對 source 執行LPUSH 或RPUSH 命令為止。
超時參數 timeout 接受一個以秒為單位的數字作為值。超時參數設為 0 表示阻塞時間可以無限期延長(block indefinitely) 。
時間復雜度: O(1)
返回值:
假如在指定時間內沒有任何元素被彈出,則返回一個 nil 和等待時長。
反之,返回一個含有兩個元素的列表,第一個元素是被彈出元素的值,第二個元素是等待時長。
127.0.0.1:6379[15]> BRPOPLPUSH msg reciver 500
"hello"
(84.71s)
127.0.0.1:6379[15]> LLEN reciver
(integer) 1
127.0.0.1:6379[15]> LRANGE reciver 0 0
1) "hello"
127.0.0.1:6379[15]> BRPOPLPUSH msg reciver 1
(nil)
(1.82s)