一、需知
1、入隊
rPush
:把值插到列表的右邊(尾部)r = rightlPush
:把值插到列表的左邊(頭部) l = left
2、出隊
rPop
:移除列表的最後一個元素,返回值爲移除的元素。(右邊,尾部)lPop
:移出並獲取列表的第一個元素(左邊,頭部)
3、阻塞等待
如果在規定時間timeOut內,沒有數據,則會掛起等待。
(1)、 brPop
:
- 命令移出並獲取列表的最後一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。
- 假如在指定時間內沒有任何元素被彈出,則返回一個 nil 和等待時長。 反之,返回一個含有兩個元素的列表,第一個元素是被彈出元素所屬的 key ,第二個元素是被彈出元素的值。
(2)、blPop
:
- 命令移出並獲取列表的第一個元素, 如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素爲止。
- 如果列表爲空,返回一個 nil 。 否則,返回一個含有兩個元素的列表,第一個元素是被彈出元素所屬的 key ,第二個元素是被彈出元素的值。
- 第一個參數是key值,第二個參數timeOut是等待的時間,如果指定的列表存在數據則返回第一個元素,否則等待timeOut秒後返回nil
二、思路
1、入隊出隊
- 如果從左邊入隊(lPush),那麼出隊就是往右邊(rPop);
- 如果從右邊入隊(rPush),那麼出隊就是往左邊( lPop);
2、實現
- 代碼中入隊是正常的業務邏輯,出隊則是監聽一個死循環
while(true){ }
方法,大致語法如下:
//從左邊(頭部取出數據)
public function redisOut(){
while (true){
//從右邊(rPush)入隊,左邊阻塞出隊
$data = $this->redis->blPop('tianPeng', 10);
if ($data){
/*
...
處理相關業務邏輯
...
*/
var_dump($data);
echo PHP_EOL;
}else{
echo '等待中...' . date('Y-m-d H:i:s') . PHP_EOL;
}
}
}
- redisOut 打印大概是這個樣子
3、問題
- 出隊
不能使用 rPop,lPop
,因爲這兩個方法是個長連接
,一直連着Redis,redis報錯如下:
[RedisException]
通常每個套接字地址(協議/網絡地址/端口)只允許使用一次。
那就使用 brPop,blPop
。
三、完整代碼
<?php
namespace app\index\controller;
use app\common\exception\BaseException;
class Tianpeng extends Base
{
public $redis;
public function __construct()
{
parent::__construct();
$this->redis = self::getRedisConn();
}
public function getRedisConn(){
try{
$redis = new \Redis(); //直接用自己安裝的Redis擴展
$connect = $redis->connect('127.0.0.1', '6379'); //主機、端口號
$password = ''; //密碼
$authConnect = true;
if (!empty($password)) {
$authConnect = $redis->auth($password);
}
$redis->select(1); //存放的數據庫索引
if(!$connect || !$authConnect){ # 因爲phpredis在連接失敗時,不會拋出異常,只返回false
throw new BaseException('redis網絡錯誤請刷新!');
}
return $redis;
}catch (\Exception $e){
throw $e;
}
}
//從右邊(尾部插入數據)
public function redisIn(){
for ($i = 1; $i <= 10; $i++){
sleep(1);
$date = date('Y-m-d H:i:s');
echo $date . '<br>';
//如果存入的數據是數組,就用json_encode轉爲字符串,再存
//$data = json_encode($data, JSON_UNESCAPED_UNICODE);
$this->redis->rPush('tianPeng', $date);
}
}
//從左邊(頭部取出數據)
public function redisOut(){
while (true){
//從右邊(rPush)入隊,左邊阻塞出隊
$data = $this->redis->blPop('tianPeng', 10);
if ($data){
/*
...
處理相關業務邏輯
...
*/
var_dump($data);
echo PHP_EOL;
}else{
echo '等待中...' . date('Y-m-d H:i:s') . PHP_EOL;
}
}
}
}
四、有話要說
如有錯誤,望各位大佬批評指正,感激不盡 >_<