Table des matières
php自己实现memcached的队列类
Maison développement back-end tutoriel php php自己实现memcached的队列类_PHP教程

php自己实现memcached的队列类_PHP教程

Jul 13, 2016 am 09:54 AM
队列

php自己实现memcached的队列类

 

 

<!--?php
/*
 * memcache队列类
 * 支持多进程并发写入、读取
 * 边写边读,AB面轮值替换
 * @author guoyu
 * @create on 9:25 2014-9-28
 * @qq技术行业交流群:136112330
 *
 * @example:
 *      $obj = new memcacheQueue(&#39;duilie&#39;);
 *      $obj--->add(&#39;1asdf&#39;);
 *      $obj->getQueueLength();
 *      $obj->read(11);
 *      $obj->get(8);
 */

class memcacheQueue{
    public static   $client;            //memcache客户端连接
    public          $access;            //队列是否可更新   
    private         $currentSide;       //当前轮值的队列面:A/B
    private         $lastSide;          //上一轮值的队列面:A/B
    private         $sideAHead;         //A面队首值
    private         $sideATail;         //A面队尾值
    private         $sideBHead;         //B面队首值
    private         $sideBTail;         //B面队尾值
    private         $currentHead;       //当前队首值
    private         $currentTail;       //当前队尾值
    private         $lastHead;          //上轮队首值
    private         $lastTail;          //上轮队尾值 
    private         $expire;            //过期时间,秒,1~2592000,即30天内;0为永不过期
    private         $sleepTime;         //等待解锁时间,微秒
    private         $queueName;         //队列名称,唯一值
    private         $retryNum;          //重试次数,= 10 * 理论并发数

    const   MAXNUM      = 2000;                 //(单面)最大队列数,建议上限10K
    const   HEAD_KEY    = &#39;_lkkQueueHead_&#39;;     //队列首kye
    const   TAIL_KEY    = &#39;_lkkQueueTail_&#39;;     //队列尾key
    const   VALU_KEY    = &#39;_lkkQueueValu_&#39;;     //队列值key
    const   LOCK_KEY    = &#39;_lkkQueueLock_&#39;;     //队列锁key
    const   SIDE_KEY    = &#39;_lkkQueueSide_&#39;;     //轮值面key

    /*
     * 构造函数
     * @param   [config]    array   memcache服务器参数
     * @param   [queueName] string  队列名称
     * @param   [expire]    string  过期时间
     * @return  NULL
     */
    public function __construct($queueName =&#39;&#39;,$expire=&#39;&#39;,$config =&#39;&#39;){
        if(empty($config)){
            self::$client = memcache_pconnect(&#39;localhost&#39;,11211);
        }elseif(is_array($config)){//array(&#39;host&#39;=>&#39;127.0.0.1&#39;,&#39;port&#39;=>&#39;11211&#39;)
            self::$client = memcache_pconnect($config[&#39;host&#39;],$config[&#39;port&#39;]);
        }elseif(is_string($config)){//"127.0.0.1:11211"
            $tmp = explode(&#39;:&#39;,$config);
            $conf[&#39;host&#39;] = isset($tmp[0]) ? $tmp[0] : &#39;127.0.0.1&#39;;
            $conf[&#39;port&#39;] = isset($tmp[1]) ? $tmp[1] : &#39;11211&#39;;
            self::$client = memcache_pconnect($conf[&#39;host&#39;],$conf[&#39;port&#39;]);     
        }
        if(!self::$client) return false;

        ignore_user_abort(TRUE);//当客户断开连接,允许继续执行
        set_time_limit(0);//取消脚本执行延时上限

        $this->access = false;
        $this->sleepTime = 1000;
        $expire = (empty($expire) && $expire!=0) ? 3600 : (int)$expire;
        $this->expire = $expire;
        $this->queueName = $queueName;
        $this->retryNum = 10000;

        $side = memcache_add(self::$client, $queueName . self::SIDE_KEY, &#39;A&#39;,false, $expire);
        $this->getHeadNTail($queueName);
        if(!isset($this->sideAHead) || empty($this->sideAHead)) $this->sideAHead = 0;
        if(!isset($this->sideATail) || empty($this->sideATail)) $this->sideATail = 0;
        if(!isset($this->sideBHead) || empty($this->sideBHead)) $this->sideBHead = 0;
        if(!isset($this->sideBHead) || empty($this->sideBHead)) $this->sideBHead = 0;
    }

    /*
     * 获取队列首尾值
     * @param   [queueName] string  队列名称
     * @return  NULL
     */
    private function getHeadNTail($queueName){
        $this->sideAHead = (int)memcache_get(self::$client, $queueName.&#39;A&#39;. self::HEAD_KEY);
        $this->sideATail = (int)memcache_get(self::$client, $queueName.&#39;A&#39;. self::TAIL_KEY);
        $this->sideBHead = (int)memcache_get(self::$client, $queueName.&#39;B&#39;. self::HEAD_KEY);
        $this->sideBTail = (int)memcache_get(self::$client, $queueName.&#39;B&#39;. self::TAIL_KEY);
    }

    /*
     * 获取当前轮值的队列面
     * @return  string  队列面名称
     */
    public function getCurrentSide(){
        $currentSide = memcache_get(self::$client, $this->queueName . self::SIDE_KEY);
        if($currentSide == &#39;A&#39;){
            $this->currentSide = &#39;A&#39;;
            $this->lastSide = &#39;B&#39;;  

            $this->currentHead  = $this->sideAHead;
            $this->currentTail  = $this->sideATail;
            $this->lastHead     = $this->sideBHead;
            $this->lastTail     = $this->sideBTail;         
        }else{
            $this->currentSide = &#39;B&#39;;
            $this->lastSide = &#39;A&#39;;

            $this->currentHead  = $this->sideBHead;
            $this->currentTail  = $this->sideBTail;
            $this->lastHead     = $this->sideAHead;
            $this->lastTail     = $this->sideATail;                     
        }

        return $this->currentSide;
    }

    /*
     * 队列加锁
     * @return boolean
     */
    private function getLock(){
        if($this->access === false){
            while(!memcache_add(self::$client, $this->queueName .self::LOCK_KEY, 1, false, $this->expire) ){
                usleep($this->sleepTime);
                @$i++;
                if($i > $this->retryNum){//尝试等待N次
                    return false;
                    break;
                }
            }
            return $this->access = true;
        }
        return false;
    }

    /*
     * 队列解锁
     * @return NULL
     */
    private function unLock(){
        memcache_delete(self::$client, $this->queueName .self::LOCK_KEY);
        $this->access = false;
    }

    /*
     * 添加数据
     * @param   [data]  要存储的值
     * @return  boolean
     */
    public function add($data){
        $result = false;
        if(!$this->getLock()){
            return $result;
        } 
        $this->getHeadNTail($this->queueName);
        $this->getCurrentSide();

        if($this->isFull()){
            $this->unLock();
            return false;
        }

        if($this->currentTail < self::MAXNUM){
            $value_key = $this->queueName .$this->currentSide . self::VALU_KEY . $this->currentTail;
            if(memcache_add(self::$client, $value_key, $data, false, $this->expire)){
                $this->changeTail();
                $result = true;
            }
        }else{//当前队列已满,更换轮值面
            $this->unLock();
            $this->changeCurrentSide();
            return $this->add($data);
        }

        $this->unLock();
        return $result;
    }

    /*
     * 取出数据
     * @param   [length]    int 数据的长度
     * @return  array
     */
    public function get($length=0){
        if(!is_numeric($length)) return false;
        if(empty($length)) $length = self::MAXNUM * 2;//默认读取所有
        if(!$this->getLock()) return false;

        if($this->isEmpty()){
            $this->unLock();
            return false;
        }

        $keyArray   = $this->getKeyArray($length);
        $lastKey    = $keyArray[&#39;lastKey&#39;];
        $currentKey = $keyArray[&#39;currentKey&#39;];
        $keys       = $keyArray[&#39;keys&#39;];
        $this->changeHead($this->lastSide,$lastKey);
        $this->changeHead($this->currentSide,$currentKey);

        $data   = @memcache_get(self::$client, $keys);
        foreach($keys as $v){//取出之后删除
            @memcache_delete(self::$client, $v, 0);
        }
        $this->unLock();

        return $data;
    }

    /*
     * 读取数据
     * @param   [length]    int 数据的长度
     * @return  array
     */
    public function read($length=0){
        if(!is_numeric($length)) return false;
        if(empty($length)) $length = self::MAXNUM * 2;//默认读取所有
        $keyArray   = $this->getKeyArray($length);
        $data   = @memcache_get(self::$client, $keyArray[&#39;keys&#39;]);
        return $data;
    }

    /*
     * 获取队列某段长度的key数组
     * @param   [length]    int 队列长度
     * @return  array
     */
    private function getKeyArray($length){
        $result = array(&#39;keys&#39;=>array(),&#39;lastKey&#39;=>array(),&#39;currentKey&#39;=>array());
        $this->getHeadNTail($this->queueName);
        $this->getCurrentSide();
        if(empty($length)) return $result;

        //先取上一面的key
        $i = $result[&#39;lastKey&#39;] = 0;
        for($i=0;$i<$length;$i++){
            $result[&#39;lastKey&#39;] = $this->lastHead + $i;
            if($result[&#39;lastKey&#39;] >= $this->lastTail) break;
            $result[&#39;keys&#39;][] = $this->queueName .$this->lastSide . self::VALU_KEY . $result[&#39;lastKey&#39;];
        }

        //再取当前面的key
        $j = $length - $i;
        $k = $result[&#39;currentKey&#39;] = 0;
        for($k=0;$k<$j;$k++){
            $result[&#39;currentKey&#39;] = $this->currentHead + $k;
            if($result[&#39;currentKey&#39;] >= $this->currentTail) break;
            $result[&#39;keys&#39;][] = $this->queueName .$this->currentSide . self::VALU_KEY . $result[&#39;currentKey&#39;];
        }

        return $result;
    }

    /*
     * 更新当前轮值面队列尾的值
     * @return  NULL
     */
    private function changeTail(){
        $tail_key = $this->queueName .$this->currentSide . self::TAIL_KEY;
        memcache_add(self::$client, $tail_key, 0,false, $this->expire);//如果没有,则插入;有则false;
        //memcache_increment(self::$client, $tail_key, 1);//队列尾+1
        $v = memcache_get(self::$client, $tail_key) +1;
        memcache_set(self::$client, $tail_key,$v,false,$this->expire);
    }

    /*
     * 更新队列首的值
     * @param   [side]      string  要更新的面
     * @param   [headValue] int     队列首的值
     * @return  NULL
     */
    private function changeHead($side,$headValue){
        if($headValue < 1) return false;
        $head_key = $this->queueName .$side . self::HEAD_KEY;
        $tail_key = $this->queueName .$side . self::TAIL_KEY;
        $sideTail = memcache_get(self::$client, $tail_key);
        if($headValue < $sideTail){
            memcache_set(self::$client, $head_key,$headValue+1,false,$this->expire);
        }elseif($headValue >= $sideTail){
            $this->resetSide($side);
        }
    }

    /*
     * 重置队列面,即将该队列面的队首、队尾值置为0
     * @param   [side]  string  要重置的面
     * @return  NULL
     */
    private function resetSide($side){
        $head_key = $this->queueName .$side . self::HEAD_KEY;
        $tail_key = $this->queueName .$side . self::TAIL_KEY;
        memcache_set(self::$client, $head_key,0,false,$this->expire);
        memcache_set(self::$client, $tail_key,0,false,$this->expire);
    }

    /*
     * 改变当前轮值队列面
     * @return  string
     */
    private function changeCurrentSide(){
        $currentSide = memcache_get(self::$client, $this->queueName . self::SIDE_KEY);
        if($currentSide == &#39;A&#39;){
            memcache_set(self::$client, $this->queueName . self::SIDE_KEY,&#39;B&#39;,false,$this->expire);
            $this->currentSide = &#39;B&#39;;
        }else{
            memcache_set(self::$client, $this->queueName . self::SIDE_KEY,&#39;A&#39;,false,$this->expire);
            $this->currentSide = &#39;A&#39;;
        }
        return $this->currentSide;
    }

    /*
     * 检查当前队列是否已满
     * @return  boolean
     */
    public function isFull(){
        $result = false;
        if($this->sideATail == self::MAXNUM && $this->sideBTail == self::MAXNUM){
            $result = true;
        }
        return $result;
    }

    /*
     * 检查当前队列是否为空
     * @return  boolean
     */
    public function isEmpty(){
        $result = true;
        if($this->sideATail > 0 || $this->sideBTail > 0){
            $result = false;
        }
        return $result;
    }

    /*
     * 获取当前队列的长度
     * 该长度为理论长度,某些元素由于过期失效而丢失,真实长度小于或等于该长度
     * @return  int
     */
    public function getQueueLength(){
        $this->getHeadNTail($this->queueName);
        $this->getCurrentSide();

        $sideALength = $this->sideATail - $this->sideAHead;
        $sideBLength = $this->sideBTail - $this->sideBHead;
        $result = $sideALength + $sideBLength;

        return $result;
    }

    /*
     * 清空当前队列数据,仅保留HEAD_KEY、TAIL_KEY、SIDE_KEY三个key
     * @return  boolean
     */
    public function clear(){
        if(!$this->getLock()) return false;
        for($i=0;$i<self::maxnum;$i++){ this-="">queueName.&#39;A&#39;. self::VALU_KEY .$i, 0);
            @memcache_delete(self::$client, $this->queueName.&#39;B&#39;. self::VALU_KEY .$i, 0);
        }
        $this->unLock();
        $this->resetSide(&#39;A&#39;);
        $this->resetSide(&#39;B&#39;);
        return true;
    }

    /*
     * 清除所有memcache缓存数据
     * @return  NULL
     */
    public function memFlush(){
        memcache_flush(self::$client);
    }

}
</self::maxnum;$i++){>
Copier après la connexion


 

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/994954.htmlTechArticlephp自己实现memcached的队列类 add(1asdf); * $obj-getQueueLength(); * $obj-read(11); * $obj-get(8); */class memcacheQueue{ public static $client; //memcache客户端连接 pu...
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Deque en Python : implémentation de files d'attente et de piles efficaces Deque en Python : implémentation de files d'attente et de piles efficaces Apr 12, 2023 pm 09:46 PM

deque en Python est un deque de bas niveau hautement optimisé, utile pour implémenter des files d'attente et des piles Pythoniques élégantes et efficaces, qui sont les types de données basés sur des listes les plus courants en informatique. Dans cet article, Yun Duojun apprendra ce qui suit avec vous : Commencez à utiliser deque pour afficher et ajouter efficacement des éléments. Accédez à n'importe quel élément de deque. Utilisez deque pour créer une file d'attente efficace. une liste Python et des éléments contextuels. Les opérations sont généralement très efficaces. Si la complexité temporelle est exprimée en Big O, alors on peut dire qu'ils sont O(1). Et lorsque Python doit réallouer de la mémoire pour augmenter la liste sous-jacente afin d'accepter de nouveaux éléments, ces

Comment utiliser Supervisor pour gérer la file d'attente ThinkPHP6 ? Comment utiliser Supervisor pour gérer la file d'attente ThinkPHP6 ? Jun 12, 2023 am 08:51 AM

À mesure que les applications Web continuent de se développer, nous devons gérer un grand nombre de tâches pour maintenir la stabilité et la disponibilité de l'application. Utiliser un système de file d’attente est une solution. ThinkPHP6 fournit un système de file d'attente intégré pour gérer les tâches. Cependant, gérer un grand nombre de tâches nécessite une meilleure gestion des files d'attente, ce qui peut être réalisé à l'aide de Supervisor. Cet article explique comment utiliser Supervisor pour gérer les files d'attente ThinkPHP6. Avant cela, nous devons comprendre quelques concepts de base : le système de file d'attente est

Application de la technologie de file d'attente au délai de message et aux nouvelles tentatives de message en PHP et MySQL Application de la technologie de file d'attente au délai de message et aux nouvelles tentatives de message en PHP et MySQL Oct 15, 2023 pm 02:26 PM

Application de la technologie de file d'attente au délai de message et aux nouvelles tentatives de message dans PHP et MySQL Résumé : Avec le développement continu des applications Web, la demande de traitement hautement simultané et de fiabilité du système devient de plus en plus élevée. En tant que solution, la technologie de file d'attente est largement utilisée dans PHP et MySQL pour implémenter des fonctions de délai de message et de nouvelle tentative de message. Cet article présentera l'application de la technologie de file d'attente dans PHP et MySQL, y compris les principes de base des files d'attente, les méthodes d'utilisation des files d'attente pour implémenter le délai de message et les méthodes d'utilisation des files d'attente pour implémenter les nouvelles tentatives de message, et donnera

Stratégies d'analyse et d'optimisation des performances des files d'attente Java Queue Stratégies d'analyse et d'optimisation des performances des files d'attente Java Queue Jan 09, 2024 pm 05:02 PM

Analyse des performances et stratégie d'optimisation de JavaQueue Résumé de la file d'attente : La file d'attente (file d'attente) est l'une des structures de données couramment utilisées en Java et est largement utilisée dans divers scénarios. Cet article abordera les problèmes de performances des files d'attente JavaQueue sous deux aspects : l'analyse des performances et les stratégies d'optimisation, et donnera des exemples de code spécifiques. Introduction La file d'attente est une structure de données premier entré, premier sorti (FIFO) qui peut être utilisée pour implémenter le mode producteur-consommateur, la file d'attente des tâches du pool de threads et d'autres scénarios. Java fournit une variété d'implémentations de files d'attente, telles que Arr

En Java, quelle est la différence entre la méthode add() et la méthode offer() dans la file d'attente ? En Java, quelle est la différence entre la méthode add() et la méthode offer() dans la file d'attente ? Aug 27, 2023 pm 02:25 PM

La file d'attente en Java est une structure de données linéaire avec plusieurs fonctions. La file d'attente a deux points de terminaison et suit le principe premier entré, premier sorti (FIFO) pour insérer et supprimer ses éléments. Dans ce didacticiel, nous découvrirons deux fonctions importantes des files d'attente en Java, à savoir add() et Offer(). Qu'est-ce qu'une file d'attente ? Queue en Java est une interface qui étend les packages util et collection. Les éléments sont insérés dans le backend et supprimés du frontend. Les files d'attente en Java peuvent être implémentées à l'aide de classes telles que les listes chaînées, DeQueue et les files d'attente prioritaires. Une file d'attente prioritaire est une forme étendue d'une file d'attente normale, dans laquelle chaque élément a une priorité. La méthode add() de la file d'attente est utilisée pour insérer des éléments dans la file d'attente. Il définira l'élément (comme

Plan d'implémentation de la surveillance des tâches de file d'attente et de la planification des tâches en PHP et MySQL Plan d'implémentation de la surveillance des tâches de file d'attente et de la planification des tâches en PHP et MySQL Oct 15, 2023 am 09:15 AM

Implémentation de la surveillance des tâches de file d'attente et de la planification des tâches dans PHP et MySQL Introduction Dans le développement d'applications Web modernes, la file d'attente de tâches est une technologie très importante. Grâce aux files d'attente, nous pouvons mettre en file d'attente certaines tâches qui doivent être exécutées en arrière-plan et contrôler le temps d'exécution et l'ordre des tâches grâce à la planification des tâches. Cet article présentera comment implémenter la surveillance et la planification des tâches dans PHP et MySQL, et fournira des exemples de code spécifiques. 1. Principe de fonctionnement de la file d'attente La file d'attente est une structure de données premier entré, premier sorti (FIFO) qui peut être utilisée pour

Quel est le principe et la mise en œuvre du système de file d'attente de courrier PHP ? Quel est le principe et la mise en œuvre du système de file d'attente de courrier PHP ? Sep 13, 2023 am 11:39 AM

Quel est le principe et la mise en œuvre du système de file d'attente de courrier PHP ? Avec le développement d’Internet, le courrier électronique est devenu l’un des moyens de communication indispensables dans la vie quotidienne et professionnelle des gens. Cependant, à mesure que l'entreprise se développe et que le nombre d'utilisateurs augmente, l'envoi direct d'e-mails peut entraîner une dégradation des performances du serveur, un échec de livraison des e-mails et d'autres problèmes. Pour résoudre ce problème, vous pouvez utiliser un système de file d'attente de messagerie pour envoyer et gérer des e-mails via une file d'attente série. Le principe de mise en œuvre du système de file d'attente de courrier est le suivant : Lorsque le courrier est mis en file d'attente, lorsqu'il est nécessaire d'envoyer le courrier, il ne l'est plus directement

Files d'attente dans le framework Yii : gérer efficacement les opérations asynchrones Files d'attente dans le framework Yii : gérer efficacement les opérations asynchrones Jun 21, 2023 am 10:13 AM

Avec le développement rapide d'Internet, les applications sont devenues de plus en plus importantes pour gérer un grand nombre de requêtes et de tâches simultanées. Dans de tels cas, la gestion des tâches asynchrones est essentielle car cela rend l'application plus efficace et mieux réactive aux demandes des utilisateurs. Le framework Yii fournit un composant de file d'attente pratique qui rend la gestion des opérations asynchrones plus facile et plus efficace. Dans cet article, nous explorerons l'utilisation et les avantages des files d'attente dans le framework Yii. Qu'est-ce qu'une file d'attente Une file d'attente est une structure de données utilisée pour gérer les données dans l'ordre premier entré, premier sorti (FIFO). Équipe

See all articles