首頁 後端開發 php教程 PHP memcache 環形佇列

PHP memcache 環形佇列

Jul 25, 2016 am 08:48 AM

PHP memcache 環形佇列類別。新手,沒咋學過資料結構,因為業務需要,所以只是硬著頭皮模擬的! 原形是 oschina上 lusi 分享的PHP memcache 佇列程式碼。為使隊列隨時可入可出,且不受int長度越界危險(單鏈採取Head自增的話不作處理有越界可能),所以索性改寫成環形隊列。可能還有BUG,忘見諒!
  1. /**
  2. * PHP memcache 環形隊列類
  3. * 原作者LKK/lianq.net
  4. * 修改FoxHunter
  5. * 因業務需要只保留的隊列中的Pop和Push,修改過期時間為0即永久
  6. */
  7. class MQueue
  8. {
  9. public static $client;
  10. private $expire; //過期時間,秒,1~2592000,即30天內
  11. private $sleepTime; //等待解鎖時間,微秒
  12. private $queueName; //隊列名稱,唯一值
  13. private $retryNum; //嘗試次數
  14. private $MAXNUM; //最大隊列容量
  15. private $canRewrite; //是否可以覆蓋開關,滿出來的內容從頭部開始覆蓋重寫原來的資料
  16. private $HEAD; //下一步要進入的指標位置
  17. private $TAIL; //下一步要進入的指標位置
  18. private $LEN; //佇列現有長度
  19. const LOCK_KEY = '_Fox_MQ_LOCK_'; //鎖定儲存標示
  20. const LENGTH_KEY = '_Fox_MQ_LENGTH_'; //佇列長度儲存標示
  21. constst //值佇列值 =標示
  22. const HEAD_KEY = '_Fox_MQ_HEAD_'; //佇列HEAD指標位置標示
  23. const TAIL_KEY = '_Fox_MQ_TAIL_'; //TAILIL_1,
  24. * 程式碼> 🎜> * 對於同一個$queueName,實例化時必須保障建構子的參數值一致,否則pop和push會導佇列順序混亂
  25. */
  26. public function __construct($queueName = '', $maxqueue = 1, $canRewrite = false, $expire = 0, $config = '')
  27. {
  28. if (empty($config)) {
  29. self::$client = memcache_pconnect('127.0.0.1 ', 11211);
  30. } elseif (is_array($config)) { //array('host'=>'127.0.0.1','port'=>'11211')
  31. self::$client = memcache_pconnect($config['host'], $config['port']);
  32. } elseif (is_string($config)) { //"127.0.0.1:11211"
  33. $tmp = explode( ':', $config);
  34. $conf['host'] = isset($tmp[0]) ? $tmp[0] : '127.0.0.1';
  35. $conf['port'] = isset($tmp[1]) ? $tmp[1] : '11211';
  36. self::$client = memcache_pconnect($conf['host'], $conf['port']);
  37. }
  38. if (!self::$client)
  39. return false;
  40. ignore_user_abort(true); //當客戶斷開連接,允許繼續執行
  41. set_time_limit(0); //取消腳本執行延遲上限
  42. $this->access = false;
  43. $this->sleepTime = 1000;
  44. $expire = (empty($expire)) ? 0 : (int) $expire 1;
  45. $this->expire = $expire;
  46. $this->queueName = $queueName;
  47. $this->retryNum = 20000;
  48. $this->MAXNUM = $maxqueue != null ? $maxqueue : 1;
  49. $this->canRewrite = $canRewrite;
  50. $this->getHeadAndTail();
  51. if (!isset($this->HEAD) || empty($this-> HEAD))
  52. $this->HEAD = 0;
  53. if (!isset($this->TAIL) || empty($this->TAIL))
  54. $this->TAIL = 0;
  55. if (!isset($this->LEN) || empty($this->LEN))
  56. $this->LEN = 0;
  57. }
  58. / /取得佇列首尾指標資訊與長度
  59. private function getHeadAndTail()
  60. {
  61. $this->HEAD = (int) memcache_get(self::$client, $this->queueName . self::HEmemcache_get(self::$client, $this->queueName . self::HEAD_KEY );
  62. $this->TAIL = (int) memcache_get(self::$client, $this->queueName . self::TAIL_KEY);
  63. $this->LEN = (int) memcache_get(self: :$client, $this->queueName . self::LENGTH_KEY);
  64. }
  65. // 利用memcache_add原子性加鎖
  66. private function lock()
  67. {
  68. if ($this->access === false) {
  69. $i = 0;
  70. while (!memcache_add(self::$client, $this->queueName . self::LOCK_KEY, 1, false, $this->expire)) {
  71. usleep($this->sleepTime);
  72. @$i ;
  73. if ($i > $this->retryNum) { //嘗試等待N次
  74. return false;
  75. break;
  76. }
  77. }
  78. return $this->access = true;
  79. }
  80. return false;
  81. }
  82. }
  83. return false;
  84. }
  85. }
  86. return false;
  87. }
  88. }
  89. return false; } } return false; } } return false; } } return false; } } return false; } } return false; }} > //更新頭部指標指向,指向下一個位置 private function incrHead() { //$this->getHeadAndTail(); //取得最新指標資訊,由於本方法體均在鎖內調用,其鎖內已調用了此方法,本行註釋 $this->HEAD ; //頭部指針下移 if ($this->HEAD >= $this->MAXNUM ) { $this->HEAD = 0; //邊界值修正 }
  90. ;
  91. $this->LEN--; //Head的移動由Pop觸發,所以相當於數量減少
  92. if ($this->LEN $this-> LEN = 0; //邊界值修正
  93. }
  94. ;
  95. memcache_set(self::$client, $this->queueName . self::HEAD_KEY, $this->HEAD, false, $this- >expire); //更新
  96. memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false, $this->expire); //更新
  97. }
  98. //更新尾部指標指向,指向下一個位置
  99. private function incrTail()
  100. {
  101. //$this->getHeadAndTail(); / /取得最新指針訊息,由於本方法體均在鎖內調用,其鎖內已調用了此方法,本行註釋
  102. $this->TAIL ; //尾部指針下移
  103. if ($this ->TAIL >= $this->MAXNUM) {
  104. $this->TAIL = 0; //邊界值修正
  105. }
  106. ;
  107. $this->LEN ; //Head的移動由Push觸發,所以相當於數量增加
  108. if ($this->LEN >= $this->MAXNUM) {
  109. $this->LEN = $this->MAXNUM; //邊界值長度修正
  110. }
  111. ;
  112. memcache_set(self::$client, $this->queueName . self::TAIL_KEY, $this->TAIL, false, $this->expire); //更新
  113. memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false, $this->expire); //更新
  114. }
  115. // 解鎖
  116. private function unLock()
  117. {
  118. memcache_delete(self::$client, $this->queueName . self::LOCK_KEY);
  119. $this->access = false;
  120. }
  121. //判斷是否滿隊列
  122. public function isFull()
  123. {
  124. //外部直接呼叫的時候由於沒有鎖定所以此處的值是個大概值,並不很準確,但內部呼叫由於在前面有lock,所以可信
  125. if ($this->canRewrite)
  126. return false;
  127. return $this->LEN == $this->MAXNUM ? true : false;
  128. }
  129. //判斷是否為空
  130. public function isEmpty()
  131. {
  132. //外部直接呼叫的時候由於沒有鎖定所以此處的值是個大概值,不太準確,但是內部呼叫由於在前面有lock,所以可信
  133. return $this->LEN == 0 ? true : false;
  134. }
  135. public function getLen()
  136. {
  137. //外部直接呼叫的時候由於沒有鎖所以此處的值是個大概值,並不很準確,但是內部呼叫由於在前面有lock,所以可信
  138. return $this->LEN;
  139. }
  140. /*
  141. * push值
  142. * @param mixed 值
  143. * @return bool
  144. */
  145. public function push ($data = '')
  146. {
  147. $result = false;
  148. if (empty($data))
  149. return $result;
  150. if (!$ this->lock()) {
  151. return $result;
  152. }
  153. $this->getHeadAndTail(); //取得最新指標資訊
  154. if ($this- >isFull()) { //只有在非覆寫下才有Full概念
  155. $this->unLock();
  156. return false;
  157. }
  158. if (memcache_set(self ::$client, $this->queueName . self::VALU_KEY . $this->TAIL, $data, MEMCACHE_COMPRESSED, $this->expire)) {
  159. //當推送後,發現尾部和頭部重疊(此時指針還未移動),且右邊仍有未由Head讀取的數據,那麼移動Head指針,避免尾部指針跨越Head
  160. if ($this->TAIL == $this->HEAD && $ this->LEN >= 1) {
  161. $this->incrHead();
  162. }
  163. $this->incrTail(); //移動尾部指針
  164. $result = true;
  165. }
  166. $this->unLock();
  167. return $result;
  168. }
  169. /*
  170. * Pop一個值
  171. * @ param [length] int 佇列長度
  172. * @return array
  173. */
  174. public function pop($length = 0)
  175. {
  176. if (!is_numeric($length))
  177. return false;
  178. if (!$this->lock())
  179. return false;
  180. $this->getHeadAndTail();
  181. if (empty( $length))
  182. $length = $this->LEN; //預設讀取所有
  183. if ($this->isEmpty()) {
  184. $this->unLock();
  185. return false;
  186. }
  187. //取得長度超出佇列長度後修正
  188. if ($length > $this->LEN)
  189. $length = $this->LEN;
  190. $data = $this->popKeyArray($length);
  191. $this->unLock();
  192. return $data;
  193. }
  194. /*
  195. * pop某段長度的值
  196. * @param [length] int 佇列長度
  197. * @return array
  198. */
  199. private ftion popKeyArray($length)
  200. {
  201. $result = array();
  202. if (empty($length))
  203. return $result;
  204. for ($k = 0; $k $result[] = @memcache_get(self::$client, $this->queueName . self::VALU_KEY . $this->HEAD);
  205. @memcache_delete (self::$client, $this->queueName . self::VALU_KEY . $this->HEAD, 0);
  206. //當提取值後,發現頭部和尾部重合(此時指針還未移動),且右邊沒有數據,即隊列中最後一個數據被完全掏空,此時指針停留在本地不移動,隊列長度變為0
  207. if ($this->TAIL == $this->HEAD && $this->LEN $this->LEN = 0;
  208. memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false , $this->expire); //更新
  209. break;
  210. } else {
  211. $this->incrHead(); //首尾未重合,或者重合但是仍有未讀取出的數據,皆移動HEAD指標到下一個待讀取位置
  212. }
  213. }
  214. return $result;
  215. }
  216. /*
  217. * 重設佇列
  218. * * @return NULL
  219. */
  220. private function reset($all = false)
  221. {
  222. if ($all) {
  223. memcache_delete(self::$client, $ this->queueName . self::HEAD_KEY, 0);
  224. memcache_delete(self::$client, $this->queueName . self::TAIL_KEY, 0);
  225. memcache_delete(self::$client, $f::$client, $ this->queueName . self::LENGTH_KEY, 0);
  226. } else {
  227. $this->HEAD = $this->TAIL = $this->LEN = 0;
  228. meacheache_set(selfmc:: $client, $this->queueName . self::HEAD_KEY, 0, false, $this->expire);
  229. memcache_set(self::$client, $this->queueName . self::TAIL_KEY, 0, false , $this->expire);
  230. memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, 0, false, $this->expire);
  231. }
  232. }
  233. /*
  234. * 清除所有memcache快取資料
  235. * @return NULL
  236. */
  237. public function memFlush()
  238. {
  239. meachebdush$ );
  240. }
  241. public function clear($all = false)
  242. {
  243. if (!$this->lock())
  244. return false;
  245. $this->getHeadAndTail();
  246. $Head = $this->HEAD;
  247. $Length = $this->LEN;
  248. $curr = 0;
  249. for ($i = 0 ; $i $curr = $this->$Head $i;
  250. if ($curr >= $this->MAXNUM) {
  251. $this->HEAD = $curr = 0;
  252. }
  253. @memcache_delete(self::$client, $this->queueName . self::VALU_KEY . $curr, 0);
  254. }
  255. $this->unLock();
  256. $this->reset($all);
  257. return true;
  258. }
  259. }
複製程式碼


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

會話如何劫持工作,如何在PHP中減輕它? 會話如何劫持工作,如何在PHP中減輕它? Apr 06, 2025 am 12:02 AM

會話劫持可以通過以下步驟實現:1.獲取會話ID,2.使用會話ID,3.保持會話活躍。在PHP中防範會話劫持的方法包括:1.使用session_regenerate_id()函數重新生成會話ID,2.通過數據庫存儲會話數據,3.確保所有會話數據通過HTTPS傳輸。

PHP 8.1中的枚舉(枚舉)是什麼? PHP 8.1中的枚舉(枚舉)是什麼? Apr 03, 2025 am 12:05 AM

PHP8.1中的枚舉功能通過定義命名常量增強了代碼的清晰度和類型安全性。 1)枚舉可以是整數、字符串或對象,提高了代碼可讀性和類型安全性。 2)枚舉基於類,支持面向對象特性,如遍歷和反射。 3)枚舉可用於比較和賦值,確保類型安全。 4)枚舉支持添加方法,實現複雜邏輯。 5)嚴格類型檢查和錯誤處理可避免常見錯誤。 6)枚舉減少魔法值,提升可維護性,但需注意性能優化。

描述紮實的原則及其如何應用於PHP的開發。 描述紮實的原則及其如何應用於PHP的開發。 Apr 03, 2025 am 12:04 AM

SOLID原則在PHP開發中的應用包括:1.單一職責原則(SRP):每個類只負責一個功能。 2.開閉原則(OCP):通過擴展而非修改實現變化。 3.里氏替換原則(LSP):子類可替換基類而不影響程序正確性。 4.接口隔離原則(ISP):使用細粒度接口避免依賴不使用的方法。 5.依賴倒置原則(DIP):高低層次模塊都依賴於抽象,通過依賴注入實現。

在PHPStorm中如何進行CLI模式的調試? 在PHPStorm中如何進行CLI模式的調試? Apr 01, 2025 pm 02:57 PM

在PHPStorm中如何進行CLI模式的調試?在使用PHPStorm進行開發時,有時我們需要在命令行界面(CLI)模式下調試PHP�...

如何在系統重啟後自動設置unixsocket的權限? 如何在系統重啟後自動設置unixsocket的權限? Mar 31, 2025 pm 11:54 PM

如何在系統重啟後自動設置unixsocket的權限每次系統重啟後,我們都需要執行以下命令來修改unixsocket的權限:sudo...

如何用PHP的cURL庫發送包含JSON數據的POST請求? 如何用PHP的cURL庫發送包含JSON數據的POST請求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL庫發送JSON數據在PHP開發中,經常需要與外部API進行交互,其中一種常見的方式是使用cURL庫發送POST�...

See all articles