redis隊列的實現

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');

$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裏面,如果訂閱者沒收到則該數據就丟失了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章