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 相关文章推荐
第四节 构造函数和析构函数 [4]
Oct 09 PHP
一篇不错的PHP基础学习笔记
Mar 18 PHP
利用discuz实现PHP大文件上传应用实例代码
Nov 14 PHP
ie6 动态缩略图不显示的原因
Jun 21 PHP
CI框架开发新浪微博登录接口源码完整版
May 28 PHP
ThinkPHP连接数据库的方式汇总
Dec 05 PHP
PDO的安全处理与事物处理方法
Oct 31 PHP
PHP读取zip文件的方法示例
Nov 17 PHP
PHP输出XML格式数据的方法总结
Feb 08 PHP
php实现的生成排列算法示例
Jul 25 PHP
PHP PDO和消息队列的个人理解与应用实例分析
Nov 25 PHP
PHP如何通过带尾指针的链表实现'队列'
Oct 22 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中文件读、写、删的操作(PHP中对文件和目录操作)
2012/03/06 PHP
PHP中单例模式与工厂模式详解
2017/02/17 PHP
PHP判断密码强度的方法详解
2017/05/26 PHP
PHP中递归的实现实例详解
2017/11/14 PHP
PHP高并发和大流量解决方案整理
2019/12/24 PHP
PHP解决高并发的优化方案实例
2020/12/10 PHP
javascript innerHTML、outerHTML、innerText、outerText的区别
2008/11/24 Javascript
javascript preload&amp;lazy load
2010/05/13 Javascript
javascript 弹出层组件(升级版)
2011/05/12 Javascript
jQuery EasyUI API 中文文档 - Tabs标签页/选项卡
2011/10/01 Javascript
浅析JavaScript中两种类型的全局对象/函数
2013/12/05 Javascript
JavaScript作用域与作用域链深入解析
2013/12/06 Javascript
JS实现自动定时切换的简洁网页选项卡效果
2015/10/13 Javascript
JS定时检测任务任务完成后执行下一步的解决办法
2016/12/22 Javascript
Angular ng-repeat指令实例以及扩展部分
2016/12/26 Javascript
原生js实现瀑布流布局
2017/03/08 Javascript
小程序实现发表评论功能
2018/07/06 Javascript
一步快速解决微信小程序中textarea层级太高遮挡其他组件
2019/03/04 Javascript
vue踩坑记录之数组定义和赋值问题
2019/03/20 Javascript
解决Vue中使用keepAlive不缓存问题
2020/08/04 Javascript
[01:54]TI珍贵瞬间系列(三):翻盘
2020/08/28 DOTA
简单易懂的python环境安装教程
2017/07/13 Python
解决Pycharm调用Turtle时 窗口一闪而过的问题
2019/02/16 Python
python单向循环链表原理与实现方法示例
2019/12/03 Python
Python concurrent.futures模块使用实例
2019/12/24 Python
Electrolux伊莱克斯巴西商店:家用电器、小家电和配件
2018/05/23 全球购物
编写strcpy函数
2014/06/24 面试题
毕业生个人的求职信范文
2013/12/03 职场文书
十八大演讲稿
2014/05/22 职场文书
群众路线党员个人整改措施
2014/10/27 职场文书
2015年上半年党建工作总结
2015/03/30 职场文书
高中优秀作文(范文)
2019/08/15 职场文书
Python实现查询剪贴板自动匹配信息的思路详解
2021/07/09 Python
Win11 Build 22000.51版本文件资源管理器“命令栏”和上下文菜单有什么新变化?
2021/11/21 数码科技
如何利用Python实现n*n螺旋矩阵
2022/01/18 Python
windows系统搭建WEB服务器详细教程
2022/08/05 Servers