加速处理队列的方式有不少种,多线程,多进程,多开任务(下文都统称任务)等等,这些方法在并发访问 队列(这里的队列都是指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