redis中文官網:http://www.redis.cn/
關於redis隊列的實現方式有兩種:
1、生產者消費者模式。
2、發布者訂閱者模式。
詳解:
1、生產者消費者模式。
普通版本:
比如一個隊列里面,生產者A push了一個數據進去,消費者B pop 了這個數據,那個這個隊列依舊為空。所以是一對一的。
至於是先進先出還是先進后出等,可以依照函數lpush(從隊列左邊,也就是隊首push一個數據) rpush(從隊列右邊也就是隊尾push一個數據) lpop(同理) rpop等來控制。
插入數據:
顯示數據:
取出數據:
阻塞版本:
但是上面的命令都是立即返回的,無論數據有無,關於取數據lpop有個增強版本,blpop(block left pop)阻塞版本,
使用方法:blpop key1 key2 ... keyn 10
同時預獲取多個key的值,並設置超時時間為10s,如果所有key,有些key有value就立即返回,如果所有key都沒有value就阻塞10秒返回
關於blpop多個key返回數據的順序,比如blpop mylist mylist2 5這個命令,先檢查mylist有數據就返回,如果沒有數據,就檢查mylist2依次。。。。直到所有key檢查完如果都沒有數據就阻塞。
這種從多個隊列里面取數據的方式可以用來做優先級的隊列,比如mylist隊列的優先級高於mylist2,push的時候,高優先級就push到mylist里面,普通優先級就push到mylist2里面,
這樣就會先取mylist里面的高優先級的數據來處理。
但是,如果遇到隊列的優先級等級過多,比如有(0-9999)個優先級,上面就不行了。解決思路是插入的時候先把數據取出來自己實現二分查找找出該插入的位置,用lset命令插入。
如果數據過多,比如隊列有幾十萬,可以把隊列分成幾十個或幾百個小隊列,比如0號隊列存優先級為(0-1000),1號隊列存優先級為(1001-2000)的數據,依次。。。。。
由於這種隊列模式pop出來一個后就返回了,所以處理業務的時候最好把pop寫在一個while(true){pop.....do logic}循環里面。
2、發布者訂閱者模式
概念:
三個用戶A,B,C同時都訂閱了一個channel名字叫msg,然后發布者往msg的channel里面發布了一個數據,那么A,B,C三個用戶都會收到該數據。
注意:
1、很明顯,三個用戶ABC需要阻塞。怎么收到訂閱的數據呢,肯定是依靠注冊在redis里面的回調函數。
2、發布的數據不會在redis里面復現,意思就是發布了以后,A,B,C由於種種原因沒收到就沒收到。。。。
直接上代碼:
發布者:
$redis = new Redis(); $re = $redis->connect('127.0.0.1','6379'); // var_dump($re);exit; $type = 'msg'; $msg = "fuck sem"; $result = $redis->publish($type , $msg); //同步操作,第一個參數是channel,第二個參數是數據 if (empty($result)) { echo 'publish failed'; }else{ echo 'publish success'; }
訂閱者:
$redis = new Redis(); $redis->connect('127.0.0.1','6379');
$redis->setOption(\Redis::OPT_READ_TIMEOUT, - 1 );
//重點!!!得設置不timeout,否則60內沒收到發布者的消息就會自動斷開
$type = 'msg'; $msg = "fuck sem"; // $result = $redis->publish($type , $msg); $result = $redis->subscribe(array($type) , 'callback'); //異步阻塞,有消息來自動調用callback函數 function callback($redis , $type , $msg){ //這里處理邏輯 echo $type."==>". $msg."\r\n"; }
兩種方式比較:
1、生產者消費者模式需要 消費者主動去拉數據,如果寫成死循環並且阻塞模式,就和第二種方式差不多了。
2、發布者訂閱者模式的數據並不存在於某個key里面,如果訂閱者沒收到則該數據就丟失了。