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 相关文章推荐
用户的详细注册和判断
Oct 09 PHP
PHP4与PHP3中一个不兼容问题的解决方法
Oct 09 PHP
mysql4.1以上版本连接时出现Client does not support authentication protocol问题解决办法
Mar 15 PHP
Zend studio for eclipse中使php可以调用mysql相关函数的设置方法
Oct 13 PHP
PHP写日志的实现方法
Nov 05 PHP
php简单分页类实现方法
Feb 26 PHP
教你在PHPStorm中配置Xdebug
Jul 27 PHP
简要剖析PHP的Yii框架的组件化机制的基本知识
Mar 17 PHP
laravel 中如何使用ajax和vue总结
Aug 16 PHP
PHP JWT初识及其简单示例
Oct 10 PHP
JS(jQuery)实现聊天接收到消息语言自动提醒功能详解【提示“您有新的消息请注意查收”】
Apr 16 PHP
如何在Laravel之外使用illuminate组件详解
Sep 20 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
PHILIPS AE3805收音机的分析打磨
2021/03/02 无线电
YII实现分页的方法
2014/07/09 PHP
TP5(thinkPHP5框架)基于bootstrap实现的单图上传插件用法示例
2019/05/29 PHP
jQuery + Flex 通过拖拽方式动态改变图片的代码
2011/08/03 Javascript
JavaScript中合并数组的N种方法
2014/09/16 Javascript
jQuery Ajax调用WCF服务详细教程
2015/03/31 Javascript
详解AngularJS中的表达式使用
2015/06/16 Javascript
jquery实现带渐变淡入淡出并向右依次展开的多级菜单效果实例
2015/08/22 Javascript
浅谈js构造函数的方法与原型prototype
2016/07/04 Javascript
jquery实用技巧之输入框提示语句
2016/07/28 Javascript
vue分页组件table-pagebar使用实例解析
2020/11/15 Javascript
AngularJS之依赖注入模拟实现
2016/08/19 Javascript
基于vuejs+webpack的日期选择插件
2020/05/21 Javascript
EsLint入门学习教程
2017/02/17 Javascript
微信小程序 websocket 实现SpringMVC+Spring+Mybatis
2017/08/04 Javascript
vue 弹窗时 监听手机返回键关闭弹窗功能(页面不跳转)
2019/05/10 Javascript
微信小程序实现页面监听自定义组件的触发事件
2020/11/01 Javascript
Python判断变量是否已经定义的方法
2014/08/18 Python
几行Python代码爬取3000+上市公司的信息
2019/01/24 Python
Django url,从一个页面调到另个页面的方法
2019/08/21 Python
python在不同条件下的输入与输出
2020/02/13 Python
解决Keras中Embedding层masking与Concatenate层不可调和的问题
2020/06/18 Python
Python实现哲学家就餐问题实例代码
2020/11/09 Python
python反爬虫方法的优缺点分析
2020/11/25 Python
python不同版本的_new_不同点总结
2020/12/09 Python
使用pandas读取表格数据并进行单行数据拼接的详细教程
2021/03/03 Python
HTML5新增的8类INPUT输入类型介绍
2015/07/06 HTML / CSS
英国在线珠宝店:The Jewel Hut
2017/03/20 全球购物
Sofmap官网:日本著名的数码电器专卖店
2017/05/19 全球购物
捷克建筑材料网上商店:DEK.cz
2021/03/06 全球购物
毕业生护理专业个人求职信范文
2014/01/04 职场文书
中层竞聘演讲稿
2014/01/09 职场文书
精神文明建设标语
2014/06/16 职场文书
药店采购员岗位职责
2014/09/30 职场文书
党政领导班子群众路线对照检查材料
2014/10/26 职场文书
失恋33天观后感
2015/06/11 职场文书