加速處理隊列的方式有不少種,多線程,多進程,多開任務(下文都統稱任務)等等,這些方法在併發訪問 隊列(這裏的隊列都是指redis的zset) 數據的時候,由於是共享同一個隊列,容易產生不少問題。php
在衆多解決辦法中,加鎖是最簡單粗暴的方法 (目前不考慮同時獲取鎖的清,php感受不太好處理,除非c寫擴展) 這中鎖也叫互斥鎖,就是同一時刻只有得到鎖的那個任務纔有資格去操做共享資源, 別的任務都阻塞住了,被放到了一個叫鎖池(Lock pool)的地方,什麼事情都幹不了,浪費了不少資源。redis
lock-free無鎖隊列 通常的是基於CAS(compareAndSet)實現的,可是php操做比較麻煩,得用c寫擴展bash
intcompare_and_swap (int* reg, intoldval, intnewval)
{
intold_reg_val = *reg;
if(old_reg_val == oldval)
*reg = newval;
returnold_reg_val;
}
複製代碼
這裏用redis的set實現,原理就是每個隊列訪問的時候,它都是隻取一個值的,取到值以後,存到set裏面,若是有返回0沒有則返回1,若是這個時候等於0,那麼說明正在有任務處理它,就去取隊列的下一個多線程
先生成一些測試數據併發
$redis = $this->DomainDrivenDesign('RedisLib');
$key = "cas:";
for(;;){
$value = time()+mt_rand(0,1000000);
$score = $value+mt_rand(0,1000000);
$redis->zAdd($key."zset",$value,$score);
}
複製代碼
處理數據代碼測試
$redis = $this->DomainDrivenDesign('RedisLib');
$keyZSet = "cas:zset";
$keySet = "cas:zadd";
for (; ;) {
ob_flush();
$start = 0;
$end = 0;
start:
flush();
ob_flush();
$queueVal = $redis->zRevRange($keyZSet, $start, $end)[0];
$val = $redis->sAdd($keySet, $queueVal);
if ($val == 0) {
$start++;
$end++;
goto start;
}
for (;;){
flush();
ob_flush();
echo $queueVal . "\r\n";
}
}
複製代碼
第二個for換成對應處理數據的代碼就好了ui
測試一下,這裏同時開了3個 this
第一個 spa