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的正则处理函数总结分析
Jun 20 PHP
php下正则来匹配dede模板标签的代码
Aug 21 PHP
php中的三元运算符使用说明
Jul 03 PHP
PHP读取txt文件的内容并赋值给数组的代码
Nov 03 PHP
php随机输出名人名言的代码
Oct 07 PHP
PHP屏蔽蜘蛛访问代码及常用搜索引擎的HTTP_USER_AGENT
Mar 06 PHP
PHP中使用sleep函数实现定时任务实例分享
Aug 21 PHP
php实现求相对时间函数
Jun 15 PHP
PHP实现上传文件并存进数据库的方法
Jul 16 PHP
yii2分页之实现跳转到具体某页的实例代码
Jun 02 PHP
laravel-admin 管理平台获取当前登陆用户信息的例子
Oct 08 PHP
在laravel中实现ORM模型使用第二个数据库设置
Oct 24 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 多维数组排序实现代码
2009/08/05 PHP
php正则取img标记中任意属性(正则替换去掉或改变图片img标记中的任意属性)
2013/08/13 PHP
destoon实现VIP排名一直在前面排序的方法
2014/08/21 PHP
PHP字符串word末字符实现大小写互换的方法
2014/11/10 PHP
Smarty模板引擎缓存机制详解
2016/05/23 PHP
js parsefloat parseint 转换函数
2010/01/21 Javascript
js使浏览器窗口最大化实现代码(适用于IE)
2013/08/07 Javascript
深入解析JavaScript中的变量作用域
2013/12/06 Javascript
微信小程序 textarea 组件详解及简单实例
2017/01/10 Javascript
利用HTML5+Socket.io实现摇一摇控制PC端歌曲切换
2017/01/13 Javascript
javascript实现秒表计时器的制作方法
2017/02/16 Javascript
vuejs使用递归组件实现树形目录的方法
2017/09/30 Javascript
javascript自定义事件功能与用法实例分析
2017/11/08 Javascript
JavaScript比较同一天的时间大小实例代码
2018/02/09 Javascript
实战node静态文件服务器的示例代码
2018/03/08 Javascript
js jquery 获取某一元素到浏览器顶端的距离实现方法
2018/09/05 jQuery
微信小程序事件对象中e.target和e.currentTarget的区别详解
2019/05/08 Javascript
mpvue实现左侧导航与右侧内容的联动
2019/10/21 Javascript
JS实现贪吃蛇游戏
2019/11/15 Javascript
js实现表格单列按字母排序
2020/08/12 Javascript
[44:21]Ti4 循环赛第四日 附加赛NEWBEE vs LGD
2014/07/13 DOTA
[36:33]2018DOTA2亚洲邀请赛 4.3 突围赛 EG vs Newbee 第二场
2018/04/04 DOTA
Python使用正则匹配实现抓图代码分享
2015/04/02 Python
Python中的进程分支fork和exec详解
2015/04/11 Python
Python设计模式之建造者模式实例详解
2019/01/17 Python
Django中自定义admin Xadmin的实现代码
2019/08/09 Python
np.newaxis 实现为 numpy.ndarray(多维数组)增加一个轴
2019/11/30 Python
Python自定义sorted排序实现方法详解
2020/09/18 Python
浅析HTML5中header标签的用法
2016/06/24 HTML / CSS
Rockport乐步美国官网:风靡美国的白宫鞋
2016/11/24 全球购物
简短大学毕业感言
2014/01/18 职场文书
数据保密承诺书
2014/06/03 职场文书
学校督导评估方案
2014/06/10 职场文书
沙滩主题婚礼活动策划方案
2014/09/15 职场文书
酒店人事专员岗位职责
2015/04/07 职场文书
新闻稿件写作技巧
2015/07/18 职场文书