1.RPOPLPUSH
LPOPLPUSH 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相同,則列表中的表尾元素被移動到表頭,並返回該元素,可以把這種特殊情況視作為列表的旋轉操作。
傳回值:
被彈出的元素。
命令:
# source 和 destination 不同redis> LRANGE alpha 0 -1 # 查看所有元素1) "a"2) "b"3) "c"4) "d"redis> RPOPLPUSH alpha reciver # 執行一次 RPOPLPUSH 看看"d"redis> LRANGE alpha 0 -11) "a"2) "b"3) "c"redis> LRANGE reciver 0 -11) "d"redis> RPOPLPUSH alpha reciver # 再執行一次,證實 RPOP 和 LPUSH 的位置正確"c"redis> LRANGE alpha 0 -11) "a"2) "b"redis> LRANGE reciver 0 -11) "c"2) "d" # source 和 destination 相同redis> LRANGE number 0 -11) "1"2) "2"3) "3"4) "4"redis> RPOPLPUSH number number"4"redis> LRANGE number 0 -1 # 4 被旋轉到了表頭1) "4"2) "1"3) "2"4) "3"redis> RPOPLPUSH number number"3"redis> LRANGE number 0 -1 # 這次是 3 被旋轉到了表頭1) "3"2) "4"3) "1"4) "2"
模式:安全地隊列
Redis的列表經常被用作隊列(queue),用於在不同程式之間有序地交換訊息,一個用戶端通過LPUSH命令將訊息放入到隊列中,而另一個用戶端通過RPOP或者BRPOP命令取出隊列中等待時間最長的訊息。
不幸的是,上面的隊列方法是不安全的,因為在這個過程中,一個用戶端可能在取出一個訊息之後崩潰,而未處理完的訊息也就因此丟失。
使用RPOPLPUSH命令可以解決這個問題,因為它不僅返回一個訊息,同時還將這個訊息添加到另一個備份列表當中,如果一切正常的話,當一個用戶端完成某個訊息的處理之後,可以用LREM命令將這個訊息從備份表刪除。
最後,還可以添加一個用戶端專門用於監視備份表,它自動地將超過一個處理
時限的訊息重新放入隊列中去(負責處理該訊息的用戶端可能已經崩潰),這樣就不會丟失任何訊息了。
模式:迴圈列表
通過使用相同的key作為RPOPLPUSH命令的兩個參數,用戶端可以用一個接一個地擷取列表元素的方式,取得列表的所有元素,而不必像LRANGE命令那樣一下子將所有列表元素都從伺服器傳送到用戶端中(兩種方式的總複雜度都是o(N))。
以上模式甚至在以下的兩個情況下也能正常工作:
①有多個用戶端同時對一個列表進行旋轉,它們擷取不同的元素,知道所有元素都被讀取完,之後又從頭開始。
②有用戶端在向列表尾部(右邊)添加新元素。
這個模式使得我們可以很容易實現這樣一類系統:有N個用戶端,需要連續不斷地對一些元素進行處理,而且處理的過程必須儘可能快。一個典型的例子就是伺服器的監控程式:它們需要在儘可能短的時間內,並行地檢查一組網站,確保它們的可訪問性。
注意:使用這個模式的用戶端是易於擴充且安全地,因為就算接收到元素的用戶端失敗,元素還是儲存在列表裡面,不會丟失,等到下個迭代來臨的時候,別的用戶端又可以繼續處理這些元素了。
2.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存在但不是清單類型時,返回一個錯誤。
傳回值:
執行RPUSH操作後,表的長度。
命令:
# 添加單個元素redis> RPUSH languages c(integer) 1# 添加重複元素redis> RPUSH languages c(integer) 2redis> LRANGE languages 0 -1 # 列表允許重複元素1) "c"2) "c"# 添加多個元素redis> RPUSH mylist a b c(integer) 3redis> LRANGE mylist 0 -11) "a"2) "b"3) "c"
3.RPUSHX
RPUSH key value
將值value插入到列表key的表尾,若且唯若key存在並且是一個非空列表。
和RPUSH命令相反,當key不存在時,RPUSH命令什麼也不做。
傳回值:
RPUSHX命令執行之後,表的長度
命令:
# key不存在redis> LLEN greet(integer) 0redis> RPUSHX greet "hello" # 對不存在的 key 進行 RPUSHX,PUSH 失敗。(integer) 0# key 存在且是一個非空列表redis> RPUSH greet "hi" # 先用 RPUSH 插入一個元素(integer) 1redis> RPUSHX greet "hello" # greet 現在是一個清單類型,RPUSHX 操作成功。(integer) 2redis> LRANGE greet 0 -11) "hi"2) "hello"
4.BLPOP
BLPOP key [key ... ] timeout
BLPOP是列表的阻塞式彈出原語。
它是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”這樣的順序,第一個找到的非空列表。
命令:
redis> DEL job command request # 確保key都被刪除(integer) 0redis> LPUSH command "update system..." # 為command列表增加一個值(integer) 1redis> LPUSH request "visit page" # 為request列表增加一個值(integer) 1redis> BLPOP job command request 0 # job 列表為空白,被跳過,緊接著 command 列表的第一個元素被彈出。1) "command" # 彈出元素所屬的列表2) "update system..." # 彈出元素所屬的值
阻塞行為
如果所有給定key都不存在或包含空列表,那麼BLPOP命令將阻塞串連,直到等待逾時,或者有另外一個用戶端對給定key的任意一個執行LPUSH或RPUSH命令為止。
逾時參數timeout接受一個以秒為單位的數字作為值。逾時參數設為0表示阻塞時間可以無限延長
命令:
redis> EXISTS job # 確保兩個 key 都不存在(integer) 0redis> EXISTS command(integer) 0redis> BLPOP job command 300 # 因為key一開始不存在,所以操作會被阻塞,直到另一用戶端對 job 或者 command 列表進行 PUSH 操作。1) "job" # 這裡被 push 的是 job2) "do my home work" # 被彈出的值(26.26s) # 等待的秒數redis> BLPOP job command 5 # 等待逾時的情況(nil)(5.66s) # 等待的秒數
相同的key被多個用戶端同時阻塞
相同的key可以被多個用戶端同時阻塞
不同的用戶端被放進一個隊列中,按【先阻塞先服務】的順序為key執行BLPOP命令。
在MULTI/EXEC事物中的BLPOP
BLPOP可以用於流水線(pipline,批量地發送多個命令並讀入多個回複),但把它用在MULTI/EXEC塊當中沒有意義。因為這要求整個服務被阻塞以保證塊執行時的原子性,該行為阻止了其他用戶端執行LPUSH或RPUSH命令。
因此,一個被包裹在MULTI/EXEC塊內的BLPOP命令,行為表現就得像LPOP一樣,對空列表返回nil,對非空列表彈出的列表元素,不進行任何阻塞操作。
命令:
# 對非空列表進行操作redis> RPUSH job programming(integer) 1redis> MULTIOKredis> BLPOP job 30QUEUEDredis> EXEC # 不阻塞,立即返回1) 1) "job" 2) "programming"# 對空列表進行操作redis> LLEN job # 空列表(integer) 0redis> MULTIOKredis> BLPOP job 30QUEUEDredis> EXEC # 不阻塞,立即返回1) (nil)
傳回值:
如果列表為空白,返回一個nil。
否則,返回一個含有兩個元素的列表,第一個元素是被彈出元素所屬的key,第二個元素是被彈出元素的值。
模式:事件提醒
有時候,為了等待一個新元素到達資料中,需要使用輪詢的方式進行資料探查。
另一種更好的方式是,使用系統提供的阻塞原語,在新元素到達時立即進行處理,而新元素還沒有到達時,就一直阻塞,避免輪詢佔用資源。
對於redis,我們似乎需要一個阻塞版的SPOP命令,但實際上,使用BLPOP或者BRPOP就能很好的解決這個問題。
使用元素用戶端(消費者)可以執行類似以下的代碼:
LOOP forever WHILE SPOP(key) returns elements ... process elements ... END BRPOP helper_keyEND
添加元素的用戶端 ( 生產者 ) 則執行以下代碼:
MULTI SADD key element LPUSH helper_key xEXEC
5.BRPOP
BRPOP key [key...] timeout
BRPOP是列表的阻塞式彈出原語。
它是RPOP命令的阻塞版本,當給定列表內沒有任何元素可供彈出的時候,串連將被BRPOP命令阻塞,直到等待逾時或發現可彈出元素為止。
當給定多個key參數時,按參數key的先後順序依次檢查各個列表,彈出第一個非空列表的尾部元素。
傳回值:
假如在指定時間內沒有任何元素被彈出,則返回一個nil和等待時間長度。
反之,返回一個含有兩個元素的列表,第一個元素是被彈出元素所屬的key,第二個元素是被彈出元素的值。
命令:
redis> LLEN course(integer) 0redis> RPUSH course algorithm001(integer) 1redis> RPUSH course c++101(integer) 2redis> BRPOP course 301) "course" # 被彈出元素所屬的列表鍵2) "c++101" # 被彈出的元素