PHP基於memcache實現環形隊列的方法

來源:互聯網
上載者:User
本篇文章主要介紹PHP基於memcache實現環形隊列的方法,感興趣的朋友參考下,希望對大家有所協助。

代碼如下:

<?php/** * PHP memcache 環形隊列類 * 原作者 LKK/lianq.net * 修改 FoxHunter * 因業務需要只保留的隊列中的Pop和Push,修改到期時間為0即永久 */class MQueue{ public static $client; private $expire; //到期時間,秒,1~2592000,即30天內 private $sleepTime; //等待解鎖時間,微秒 private $queueName; //隊列名稱,唯一值 private $retryNum; //嘗試次數 private $MAXNUM; //最大隊列容量 private $canRewrite; //是否可以覆寫開關,滿出來的內容從頭部開始覆蓋重寫原來的資料 private $HEAD; //下一步要進入的指標位置 private $TAIL; //下一步要進入的指標位置 private $LEN; //隊列現有長度 const LOCK_KEY = '_Fox_MQ_LOCK_'; //鎖儲存標示 const LENGTH_KEY = '_Fox_MQ_LENGTH_'; //隊列現長度儲存標示 const VALU_KEY = '_Fox_MQ_VAL_'; //隊列KVStore for Redis標示 const HEAD_KEY = '_Fox_MQ_HEAD_'; //隊列HEAD指標位置標示 const TAIL_KEY = '_Fox_MQ_TAIL_'; //隊列TAIL指標位置標示 /*  * 建構函式  * 對於同一個$queueName,執行個體化時必須保障建構函式的參數值一致,否則pop和push會導隊列順序混亂  */ public function __construct($queueName = '', $maxqueue = 1, $canRewrite = false, $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)) ? 0 : (int) $expire + 1;  $this->expire  = $expire;  $this->queueName = $queueName;  $this->retryNum = 20000;  $this->MAXNUM  = $maxqueue != null ? $maxqueue : 1;  $this->canRewrite = $canRewrite;  $this->getHeadAndTail();  if (!isset($this->HEAD) || empty($this->HEAD))   $this->HEAD = 0;  if (!isset($this->TAIL) || empty($this->TAIL))   $this->TAIL = 0;  if (!isset($this->LEN) || empty($this->LEN))   $this->LEN = 0; } //擷取隊列首尾指標資訊和長度 private function getHeadAndTail() {  $this->HEAD = (int) memcache_get(self::$client, $this->queueName . self::HEAD_KEY);  $this->TAIL = (int) memcache_get(self::$client, $this->queueName . self::TAIL_KEY);  $this->LEN = (int) memcache_get(self::$client, $this->queueName . self::LENGTH_KEY); } // 利用memcache_add原子性加鎖 private function lock() {  if ($this->access === false) {   $i = 0;   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; } //更新頭部指標指向,指向下一個位置 private function incrHead() {  //$this->getHeadAndTail(); //擷取最新指標資訊 ,由於本方法體均在鎖內調用,其鎖內已調用了此方法,本行注釋  $this->HEAD++; //頭部指標下移  if ($this->HEAD >= $this->MAXNUM) {   $this->HEAD = 0; //邊界值修正  }  ;  $this->LEN--; //Head的移動由Pop觸發,所以相當於數量減少  if ($this->LEN < 0) {   $this->LEN = 0; //邊界值修正  }  ;  memcache_set(self::$client, $this->queueName . self::HEAD_KEY, $this->HEAD, false, $this->expire); //更新  memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false, $this->expire); //更新 } //更新尾部指標指向,指向下一個位置 private function incrTail() {  //$this->getHeadAndTail(); //擷取最新指標資訊,由於本方法體均在鎖內調用,其鎖內已調用了此方法,本行注釋  $this->TAIL++; //尾部指標下移  if ($this->TAIL >= $this->MAXNUM) {   $this->TAIL = 0; //邊界值修正  }  ;  $this->LEN++; //Head的移動由Push觸發,所以相當於數量增加  if ($this->LEN >= $this->MAXNUM) {   $this->LEN = $this->MAXNUM; //邊界值長度修正  }  ;  memcache_set(self::$client, $this->queueName . self::TAIL_KEY, $this->TAIL, false, $this->expire); //更新  memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false, $this->expire); //更新 } // 解鎖 private function unLock() {  memcache_delete(self::$client, $this->queueName . self::LOCK_KEY);  $this->access = false; } //判斷是否滿隊列 public function isFull() {  //外部直接調用的時候由於沒有鎖所以此處的值是個大概值,並不很準確,但是內部調用由於在前面有lock,所以可信  if ($this->canRewrite)   return false;  return $this->LEN == $this->MAXNUM ? true : false; } //判斷是否為空白 public function isEmpty() {  //外部直接調用的時候由於沒有鎖所以此處的值是個大概值,並不很準確,但是內部調用由於在前面有lock,所以可信  return $this->LEN == 0 ? true : false; } public function getLen() {  //外部直接調用的時候由於沒有鎖所以此處的值是個大概值,並不很準確,但是內部調用由於在前面有lock,所以可信  return $this->LEN; } /*  * push值  * @param mixed 值  * @return bool  */ public function push($data = '') {  $result = false;  if (empty($data))   return $result;  if (!$this->lock()) {   return $result;  }  $this->getHeadAndTail(); //擷取最新指標資訊  if ($this->isFull()) { //只有在非覆寫下才有Full概念   $this->unLock();   return false;  }  if (memcache_set(self::$client, $this->queueName . self::VALU_KEY . $this->TAIL, $data, MEMCACHE_COMPRESSED, $this->expire)) {   //當推送後,發現尾部和頭部重合(此時指標還未移動),且右邊仍有未由Head讀取的資料,那麼移動Head指標,避免尾部指標跨越Head   if ($this->TAIL == $this->HEAD && $this->LEN >= 1) {    $this->incrHead();   }   $this->incrTail(); //移動尾部指標   $result = true;  }  $this->unLock();  return $result; } /*  * Pop一個值  * @param [length] int 隊列長度  * @return array  */ public function pop($length = 0) {  if (!is_numeric($length))   return false;  if (!$this->lock())   return false;  $this->getHeadAndTail();  if (empty($length))   $length = $this->LEN; //預設讀取所有  if ($this->isEmpty()) {   $this->unLock();   return false;  }  //擷取長度超出隊列長度後進行修正  if ($length > $this->LEN)   $length = $this->LEN;  $data = $this->popKeyArray($length);  $this->unLock();  return $data; } /*  * pop某段長度的值  * @param [length] int 隊列長度  * @return array  */ private function popKeyArray($length) {  $result = array();  if (empty($length))   return $result;  for ($k = 0; $k < $length; $k++) {   $result[] = @memcache_get(self::$client, $this->queueName . self::VALU_KEY . $this->HEAD);   @memcache_delete(self::$client, $this->queueName . self::VALU_KEY . $this->HEAD, 0);   //當提取值後,發現頭部和尾部重合(此時指標還未移動),且右邊沒有資料,即隊列中最後一個資料被完全掏空,此時指標停留在本地不移動,隊列長度變為0   if ($this->TAIL == $this->HEAD && $this->LEN <= 1) {    $this->LEN = 0;    memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false, $this->expire); //更新    break;   } else {    $this->incrHead(); //首尾未重合,或者重合但是仍有未讀取出的資料,均移動HEAD指標到下一處待讀取位置   }  }  return $result; } /*  * 重設隊列  * * @return NULL  */ private function reset($all = false) {  if ($all) {   memcache_delete(self::$client, $this->queueName . self::HEAD_KEY, 0);   memcache_delete(self::$client, $this->queueName . self::TAIL_KEY, 0);   memcache_delete(self::$client, $this->queueName . self::LENGTH_KEY, 0);  } else {   $this->HEAD = $this->TAIL = $this->LEN = 0;   memcache_set(self::$client, $this->queueName . self::HEAD_KEY, 0, false, $this->expire);   memcache_set(self::$client, $this->queueName . self::TAIL_KEY, 0, false, $this->expire);   memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, 0, false, $this->expire);  } } /*  * 清除所有memcache快取資料  * @return NULL  */ public function memFlush() {  memcache_flush(self::$client); } public function clear($all = false) {  if (!$this->lock())   return false;  $this->getHeadAndTail();  $Head = $this->HEAD;  $Length = $this->LEN;  $curr = 0;  for ($i = 0; $i < $Length; $i++) {   $curr = $this->$Head + $i;   if ($curr >= $this->MAXNUM) {    $this->HEAD = $curr = 0;   }   @memcache_delete(self::$client, $this->queueName . self::VALU_KEY . $curr, 0);  }  $this->unLock();  $this->reset($all);  return true; }}

總結:以上就是本篇文的全部內容,希望能對大家的學習有所協助。

相關推薦:

smarty自訂資源的定義與提示

PHP的檔案操作及演算法

PHP類比asp中response類的方法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.