php基于redis的lock-free

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

第二个
第三个
相关文章
相关标签/搜索