php的memcache类分享(memcache队列)


Posted in PHP onMarch 26, 2014

memcacheQueue.class.php

<?php
/**
 * PHP memcache 队列类
 * @author LKK/lianq.net
 * @version 0.3
 * @修改说明:
 * 1.放弃了之前的AB面轮值思路,使用类似数组的构造,重写了此类.
 * 2.队列默认先进先出,但增加了反向读取功能.
 * 3.感谢网友FoxHunter提出的宝贵意见.
 * @example:
 * $obj = new memcacheQueue('duilie');
 * $obj->add('1asdf');
 * $obj->getQueueLength();
 * $obj->read(10);
 * $obj->get(8);
 */
class memcacheQueue{
 public static $client;   //memcache客户端连接
 public   $access;   //队列是否可更新
 private   $expire;   //过期时间,秒,1~2592000,即30天内
 private   $sleepTime;   //等待解锁时间,微秒
 private   $queueName;   //队列名称,唯一值
 private   $retryNum;   //重试次数,= 10 * 理论并发数
 public   $currentHead;  //当前队首值
 public   $currentTail;  //当前队尾值
 const MAXNUM  = 20000;    //最大队列数,建议上限10K
 const HEAD_KEY = '_lkkQueueHead_';  //队列首kye
 const TAIL_KEY = '_lkkQueueTail_';  //队列尾key
 const VALU_KEY = '_lkkQueueValu_';  //队列值key
 const LOCK_KEY = '_lkkQueueLock_';  //队列锁key
    /**
     * 构造函数
     * @param string $queueName  队列名称
     * @param int $expire 过期时间
     * @param array $config  memcache配置
     * 
     * @return <type>
     */
 public function __construct($queueName ='',$expire=0,$config =''){
  if(empty($config)){
   self::$client = memcache_pconnect('127.0.0.1',11211);
  }elseif(is_array($config)){//array('host'=>'127.0.0.1','port'=>'11211')
   self::$client = memcache_pconnect($config['host'],$config['port']);
  }elseif(is_string($config)){//"127.0.0.1:11211"
   $tmp = explode(':',$config);
   $conf['host'] = isset($tmp[0]) ? $tmp[0] : '127.0.0.1';
   $conf['port'] = isset($tmp[1]) ? $tmp[1] : '11211';
   self::$client = memcache_pconnect($conf['host'],$conf['port']);
  }
  if(!self::$client) return false;
  ignore_user_abort(true);//当客户断开连接,允许继续执行
  set_time_limit(0);//取消脚本执行延时上限
  $this->access = false;
  $this->sleepTime = 1000;
  $expire = empty($expire) ? 3600 : intval($expire)+1;
  $this->expire = $expire;
  $this->queueName = $queueName;
  $this->retryNum = 1000;
  $this->head_key = $this->queueName . self::HEAD_KEY;
  $this->tail_key = $this->queueName . self::TAIL_KEY;
  $this->lock_key = $this->queueName . self::LOCK_KEY;
  $this->_initSetHeadNTail();
 }
    /**
     * 初始化设置队列首尾值
     */
 private function _initSetHeadNTail(){
  //当前队列首的数值
  $this->currentHead = memcache_get(self::$client, $this->head_key);
  if($this->currentHead === false) $this->currentHead =0;
  //当前队列尾的数值
  $this->currentTail = memcache_get(self::$client, $this->tail_key);
  if($this->currentTail === false) $this->currentTail =0;
 }
    /**
     * 当取出元素时,改变队列首的数值
  * @param int $step 步长值
     */
 private function _changeHead($step=1){
  $this->currentHead += $step;
  memcache_set(self::$client, $this->head_key,$this->currentHead,false,$this->expire);
 }
    /**
     * 当添加元素时,改变队列尾的数值
  * @param int $step 步长值
     * @param bool $reverse 是否反向
     * @return null
     */
 private function _changeTail($step=1, $reverse =false){
  if(!$reverse){
   $this->currentTail += $step;
  }else{
   $this->currentTail -= $step;
  }
  memcache_set(self::$client, $this->tail_key,$this->currentTail,false,$this->expire);
 }
    /**
     * 队列是否为空
     * @return bool
     */
 private function _isEmpty(){
  return (bool)($this->currentHead === $this->currentTail);
 }
    /**
     * 队列是否已满
     * @return bool
     */
 private function _isFull(){
  $len = $this->currentTail - $this->currentHead;
  return (bool)($len === self::MAXNUM);
 }
    /**
     * 队列加锁
     */
 private function _getLock(){
  if($this->access === false){
   while(!memcache_add(self::$client, $this->lock_key, 1, false, $this->expire) ){
    usleep($this->sleepTime);
    @$i++;
    if($i > $this->retryNum){//尝试等待N次
     return false;
     break;
    }
   }
   $this->_initSetHeadNTail();
   return $this->access = true;
  }
  return $this->access;
 }
    /**
     * 队列解锁
     */
 private function _unLock(){
  memcache_delete(self::$client, $this->lock_key, 0);
  $this->access = false;
 }
    /**
     * 获取当前队列的长度
     * 该长度为理论长度,某些元素由于过期失效而丢失,真实长度<=该长度
     * @return int
     */
 public function getQueueLength(){
  $this->_initSetHeadNTail();
  return intval($this->currentTail - $this->currentHead);
 }
    /**
     * 添加队列数据
     * @param void $data 要添加的数据
     * @return bool
     */
 public function add($data){
  if(!$this->_getLock()) return false;
  if($this->_isFull()){
   $this->_unLock();
   return false;
  }
  $value_key = $this->queueName . self::VALU_KEY . strval($this->currentTail +1);
  $result = memcache_set(self::$client, $value_key, $data, MEMCACHE_COMPRESSED, $this->expire);
  if($result){
   $this->_changeTail();
  }
  $this->_unLock();
  return $result;
 }
    /**
     * 读取队列数据
     * @param int $length 要读取的长度(反向读取使用负数)
     * @return array
     */
 public function read($length=0){
  if(!is_numeric($length)) return false;
  $this->_initSetHeadNTail();
  if($this->_isEmpty()){
   return false;
  }
  if(empty($length)) $length = self::MAXNUM;//默认所有
  $keyArr = array();
  if($length >0){//正向读取(从队列首向队列尾)
   $tmpMin = $this->currentHead;
   $tmpMax = $tmpMin + $length;
   for($i= $tmpMin; $i<=$tmpMax; $i++){
    $keyArr[] = $this->queueName . self::VALU_KEY . $i;
   }
  }else{//反向读取(从队列尾向队列首)
   $tmpMax = $this->currentTail;
   $tmpMin = $tmpMax + $length;
   for($i= $tmpMax; $i >$tmpMin; $i--){
    $keyArr[] = $this->queueName . self::VALU_KEY . $i;
   }
  }
  $result = @memcache_get(self::$client, $keyArr);
  return $result;
 }
    /**
     * 取出队列数据
     * @param int $length 要取出的长度(反向读取使用负数)
     * @return array
     */
 public function get($length=0){
  if(!is_numeric($length)) return false;
  if(!$this->_getLock()) return false;
  if($this->_isEmpty()){
   $this->_unLock();
   return false;
  }
  if(empty($length)) $length = self::MAXNUM;//默认所有
  $length = intval($length);
  $keyArr = array();
  if($length >0){//正向读取(从队列首向队列尾)
   $tmpMin = $this->currentHead;
   $tmpMax = $tmpMin + $length;
   for($i= $tmpMin; $i<=$tmpMax; $i++){
    $keyArr[] = $this->queueName . self::VALU_KEY . $i;
   }
   $this->_changeHead($length);
  }else{//反向读取(从队列尾向队列首)
   $tmpMax = $this->currentTail;
   $tmpMin = $tmpMax + $length;
   for($i= $tmpMax; $i >$tmpMin; $i--){
    $keyArr[] = $this->queueName . self::VALU_KEY . $i;
   }
   $this->_changeTail(abs($length), true);
  }
  $result = @memcache_get(self::$client, $keyArr);
  foreach($keyArr as $v){//取出之后删除
   @memcache_delete(self::$client, $v, 0);
  }
  $this->_unLock();
  return $result;
 }
    /**
     * 清空队列
     */
 public function clear(){
  if(!$this->_getLock()) return false;
  if($this->_isEmpty()){
   $this->_unLock();
   return false;
  }
  $tmpMin = $this->currentHead--;
  $tmpMax = $this->currentTail++;
  for($i= $tmpMin; $i<=$tmpMax; $i++){
   $tmpKey = $this->queueName . self::VALU_KEY . $i;
   @memcache_delete(self::$client, $tmpKey, 0);
  }
  $this->currentTail = $this->currentHead = 0;
  memcache_set(self::$client, $this->head_key,$this->currentHead,false,$this->expire);
  memcache_set(self::$client, $this->tail_key,$this->currentTail,false,$this->expire);
  $this->_unLock();
 }
 /*
  * 清除所有memcache缓存数据
  */
 public function memFlush(){
  memcache_flush(self::$client);
 }
}//end class
PHP 相关文章推荐
PHP SEO优化之URL优化方法
Apr 21 PHP
php 数组的一个悲剧?
May 11 PHP
解析Linux下Varnish缓存的配置优化
Jun 20 PHP
通过PHP current函数获取未知字符键名数组第一个元素的值
Jun 24 PHP
php解析html类库simple_html_dom(详细介绍)
Jul 05 PHP
php中ltrim()、rtrim()与trim()删除字符空格实例
Nov 25 PHP
PHP中文乱码解决方案
Mar 05 PHP
discuz图片顺序混乱解决方案
Jul 29 PHP
php数组冒泡排序算法实例
May 06 PHP
PHP实现二维数组按某列进行排序的方法
Nov 18 PHP
如何离线执行php任务
Feb 21 PHP
解决laravel5中auth用户登录其他页面获取不到登录信息的问题
Oct 08 PHP
codeigniter自带数据库类使用方法说明
Mar 25 #PHP
php使用codebase生成随机数
Mar 25 #PHP
php中stream(流)的用法
Mar 25 #PHP
PHP对接微信公众平台消息接口开发流程教程
Mar 25 #PHP
php操作MongoDB基础教程(连接、新增、修改、删除、查询)
Mar 25 #PHP
php获取域名的google收录示例
Mar 24 #PHP
php 使用GD库为页面增加水印示例代码
Mar 24 #PHP
You might like
简单的移动设备检测PHP脚本代码
2011/02/19 PHP
php下载文件的代码示例
2012/06/29 PHP
php模拟ping命令(php exec函数的使用方法)
2013/10/25 PHP
使用php伪造referer的方法 利用referer防止图片盗链
2014/01/20 PHP
学习php设计模式 php实现桥梁模式(bridge)
2015/12/07 PHP
PHP实现的限制IP投票程序IP来源分析
2016/05/04 PHP
PHP 表单提交及处理表单数据详解及实例
2016/12/27 PHP
ThinkPHP 在阿里云上的nginx.config配置实例详解
2017/10/11 PHP
prettify 代码高亮着色器google出品
2010/12/28 Javascript
关于innerHTML后丢失动态绑定的EVENT问题解决方法
2013/05/19 Javascript
js动态生成Html元素实现Post操作(createElement)
2015/09/14 Javascript
PHP+MySQL+jQuery随意拖动层并即时保存拖动位置实例讲解
2015/10/09 Javascript
JS检测移动端横竖屏的代码
2016/05/30 Javascript
利用jquery实现实时更新歌词的方法
2017/01/06 Javascript
Vue 2.0 服务端渲染入门介绍
2017/03/29 Javascript
深入理解AngularJs-scope的脏检查(一)
2017/06/19 Javascript
浅析vue-router原理
2018/10/19 Javascript
使用Python简单的实现树莓派的WEB控制
2016/02/18 Python
Python实现脚本锁功能(同时只能执行一个脚本)
2017/05/10 Python
Python利用turtle库绘制彩虹代码示例
2017/12/20 Python
对Python中实现两个数的值交换的集中方法详解
2019/01/11 Python
Python----数据预处理代码实例
2019/03/20 Python
彻底理解Python中的yield关键字
2019/04/01 Python
浅谈Python 钉钉报警必备知识系统讲解
2020/08/17 Python
python实现二分查找算法
2020/09/18 Python
python的setattr函数实例用法
2020/12/16 Python
HTML5 video播放器全屏(fullScreen)方法实例
2015/04/24 HTML / CSS
床上用品全球在线购物:BeddingInn
2016/12/18 全球购物
大学生简历中个人的自我评价
2013/10/06 职场文书
机关会计岗位职责
2014/04/08 职场文书
2014年党员加强作风建设思想汇报
2014/09/15 职场文书
四风个人对照检查材料思想汇报(办公室通用版)
2014/10/07 职场文书
2015年市场部工作总结
2015/04/30 职场文书
大学生求职意向书
2015/05/11 职场文书
nginx配置虚拟主机的详细步骤
2021/07/21 Servers
Nginx反向代理、重定向
2022/04/13 Servers