加速处理队列的方式有很多种,多线程,多进程,多开任务(下文都统称任务)等等,这些方法在并发访问 队列(这里的队列都是指redis的zset) 数据的时候,因为是共享同一个队列,容易产生很多问题。
在众多解决办法中,加锁是最简单粗暴的方法 (目前不考虑同时获取锁的清,php感觉不太好处理,除非c写扩展) 这中锁也叫互斥锁,就是同一时刻只有获得锁的那个任务才有资格去操作共享资源, 别的任务都阻塞住了,被放到了一个叫锁池(Lock pool)的地方,什么事情都干不了,浪费了很多资源。
lock-free无锁队列 一般的是基于CAS(compareAndSet)实现的,但是php操作比较麻烦,得用c写扩展
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换成对应处理数据的代码就行了
测试一下,这里同时开了3个
第一个
第二个 第三个