>  기사  >  백엔드 개발  >  PHP Memcache 링 큐

PHP Memcache 링 큐

WBOY
WBOY원래의
2016-07-25 08:48:251050검색
PHP Memcache 링 큐 클래스. 저는 초보자이고 비즈니스 요구 때문에 데이터 구조에 대해 많이 배우지 않았습니다. 프로토타입은 oschina에서 lusi가 공유하는 PHP memcache 대기열 코드입니다. int 길이가 경계를 넘을 위험 없이 언제든지 대기열에 들어가고 나갈 수 있도록 하기 위해(단일 체인이 헤드 자동 증가를 채택하는 경우 처리하지 않고 경계를 넘을 가능성이 있습니다) 단순히 순환 대기열로 다시 작성됩니다.버그가 있을 수 있습니다. 죄송합니다!
  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. const VALU_KEY = '_Fox_MQ_VAL_'; 저장소 표시
  22. const HEAD_KEY = '_Fox_MQ_HEAD_'; // 큐 HEAD 포인터 위치 표시
  23. const TAIL_KEY = '_Fox_MQ_TAIL_' // 큐 TAIL 포인터 위치 표시
  24. /*
  25. * 생성자
  26. * 동일한 $queueName의 경우 생성자의 매개변수 값은 인스턴스화 시 일관되어야 합니다. 그렇지 않으면 pop 및 push가 대기열 순서에 혼란을 야기합니다.
  27. */
  28. public function __construct($queueName = ' ', $ maxqueue = 1, $canRewrite = false, $expire = 0, $config = '')
  29. {
  30. if (empty($config)) {
  31. self::$client = memcache_pconnect( '127.0.0.1', 11211);
  32. } elseif (is_array($config)) { //array('host'=>'127.0.0.1','port'=>'11211')
  33. self: :$client = memcache_pconnect($config['host'], $config['port']);
  34. } elseif (is_string($config)) { //"127.0.0.1:11211"
  35. $tmp = 폭발(':', $config);
  36. $conf['host'] = isset($tmp[0]) ? $tmp[0] : '127.0.0.1';
  37. $ conf[' port'] = isset($tmp[1]) ? $tmp[1] : '11211';
  38. self::$client = memcache_pconnect($conf['host'], $conf['port ']) ;
  39. }
  40. if (!self::$client)
  41. return false;
  42. ignore_user_abort(true); //클라이언트 연결이 끊어지면 실행을 계속하도록 허용
  43. set_time_limit( 0); //스크립트 실행 지연 상한 취소
  44. $this->access = false;
  45. $this->sleepTime = 1000;
  46. $expire = (empty($expire)) ? 0 : (int ) $expire 1;
  47. $this->expire = $expire;
  48. $this->queueName = $queueName;
  49. $this->retryNum = 20000;
  50. $this-> ;MAXNUM = $maxqueue != null ? $maxqueue : 1;
  51. $this->canRewrite = $canRewrite;
  52. $this->getHeadAndTail();
  53. if (! isset($this- >HEAD) || 비어 있음($this->HEAD))
  54. $this->HEAD = 0;
  55. if (!isset($this->TAIL) || 비어 있음($this- >TAIL))
  56. $this->TAIL = 0;
  57. if (!isset($this->LEN) || 비어 있음($this->LEN))
  58. $this- >LEN = 0;
  59. }
  60. //큐 헤드 및 테일 포인터 정보와 길이 가져오기
  61. 비공개 함수 getHeadAndTail()
  62. {
  63. $this->HEAD = (int) memcache_get(self::$client, $this->queueName . self::HEAD_KEY);
  64. $this->TAIL = (int) memcache_get(self:: $client, $this-> queueName . self::TAIL_KEY);
  65. $this->LEN = (int) memcache_get(self::$client, $this->queueName . self::LENGTH_KEY);
  66. }
  67. // memcache_add 원자 잠금 사용
  68. 개인 함수 lock()
  69. {
  70. if ($this->access === false) {
  71. $i = 0;
  72. while (!memcache_add(self::$client, $this->queueName . self::LOCK_KEY, 1, false, $this->expire)) {
  73. usleep( $this->sleepTime );
  74. @$i ;
  75. if ($i > $this->retryNum) { //N회 대기 시도
  76. return false;
  77. break;
  78. }
  79. }
  80. return $this->access = true;
  81. }
  82. return false;
  83. }
  84. //가리키도록 헤드 포인터 업데이트 다음 위치
  85. private function incrHead()
  86. {
  87. //$this->getHeadAndTail(); //이 메소드 본문은 잠금에서 호출되므로 이 메소드는 이 줄은 Comment
  88. $this->HEAD; //헤드 포인터를 아래로 이동합니다
  89. if ($this->HEAD >= $this->MAXNUM) {
  90. $this->HEAD = 0; //경계값 수정
  91. }
  92. ;
  93. $this->LEN--; //Head의 움직임은 Pop에 의해 발생하므로 수량을 줄이는 것과 같습니다
  94. if ($this->LEN < 0 ) {
  95. $ this->LEN = 0; //경계 값 수정
  96. }
  97. ;
  98. memcache_set(self::$client, $this->queueName . self::HEAD_KEY, $this->HEAD , false, $this->expire) //업데이트
  99. memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false, $this-> ;expire); //업데이트
  100. }
  101. //다음 위치를 가리키도록 테일 포인터 업데이트
  102. private function incrTail()
  103. {
  104. / /$this->getHeadAndTail(); //최신 포인터 정보를 가져옵니다. 이 메소드 본문이 잠금에서 호출되었으므로 이 행에 주석을 달았습니다. > $this->TAIL ; / /꼬리 포인터를 아래로 이동
  105. if ($this->TAIL >= $this->MAXNUM) {
  106. $this->TAIL = 0; /경계값 수정
  107. }
  108. ;
  109. $this->LEN ; //머리의 움직임은 Push에 의해 발생하므로 수량 증가와 같습니다
  110. if ($this-> LEN >= $this->MAXNUM) {
  111. $this->LEN = $this->MAXNUM; //경계 값 길이 수정
  112. }
  113. ;
  114. memcache_set(self: :$client, $this->queueName . self:: TAIL_KEY, $this->TAIL, false, $this->expire) //업데이트
  115. memcache_set(self::$client, $this- >queueName . self::LENGTH_KEY, $this-> LEN, false, $this->expire) //업데이트
  116. }
  117. // 잠금 해제
  118. unLock()
  119. {
  120. memcache_delete(self: :$client, $this->queueName . self::LOCK_KEY);
  121. $this->access = false;
  122. }
  123. //큐가 꽉 찼는지 판단
  124. public function isFull()
  125. {
  126. //외부 호출을 직접 할 경우에는 락이 걸려 있지 않으므로 여기서의 값은 대략적인 값이며, 이는 그다지 정확하지는 않습니다. 그러나 내부 호출은 앞에 잠금 장치가 있으므로 신뢰할 수 있습니다.
  127. if ($this->canRewrite)
  128. return false;
  129. return $this->LEN = = $this->MAXNUM ? true : false;
  130. }
  131. //판단 비어 있습니까?
  132. public function isEmpty()
  133. {
  134. // 외부에는 잠금 장치가 없으므로 여기에 있는 값은 대략적인 값이며 그다지 정확하지는 않습니다. 그러나 내부적으로 호출하면 앞에 잠금 장치가 있으므로 신뢰할 수 있습니다
  135. return $this->LEN == 0 ? true : false;
  136. }
  137. public function getLen()
  138. {
  139. //외부에서 직접 호출 이때는 lock이 없기 때문에 여기서의 값은 대략적인 값으로 매우 정확하지는 않습니다. 그러나 내부 호출 앞에 자물쇠가 있으므로 신뢰할 수 있습니다.
  140. return $this->LEN;
  141. }
  142. /*
  143. * 푸시 값
  144. * @param 혼합 값
  145. * @return bool
  146. */
  147. 공개 함수 push($data = '')
  148. {
  149. $result = false ;
  150. if (empty($data))
  151. return $result;
  152. if (!$this->lock()) {
  153. return $result ;
  154. }
  155. $this->getHeadAndTail(); //최신 포인터 정보 가져오기
  156. if ($this->isFull()) { //재정의되지 않은 경우에만 적어두는 방법으로만 가능 Full
  157. $this->unLock();
  158. return false;
  159. }
  160. if (memcache_set(self::$client, $this->queueName) 개념이 있습니다. . self::VALU_KEY . $this->TAIL, $data, MEMCACHE_COMPRESSED, $this->expire)) {
  161. //푸시한 후 꼬리와 머리가 겹치는 것을 발견했습니다(포인터가 일치하지 않음). 아직 이동됨)이고 오른쪽에는 여전히 Head에서 읽지 않은 데이터가 있습니다. 그런 다음 Head 포인터를 이동하여 Tail 포인터가 Head를 가로지르는 것을 방지하세요
  162. if ($this->TAIL == $this-> HEAD && $this->LEN > ;= 1) {
  163. $this->incrHead();
  164. }
  165. $this->incrTail() //꼬리 포인터 이동
  166. $result = true;
  167. }
  168. $this->unLock();
  169. return $result;
  170. }
  171. /*
  172. * 값 팝
  173. * @param [length] int 큐 길이
  174. * @return array
  175. */
  176. public function pop($length = 0)
  177. {
  178. if (! is_numeric($length))
  179. false 반환;
  180. if (!$this->lock())
  181. false 반환;
  182. $this->getHeadAndTail() ;
  183. if (empty ($length))
  184. $length = $this->LEN //기본적으로
  185. 모두 읽기 if ($this->isEmpty() ) {
  186. $this-> unLock();
  187. return false;
  188. }
  189. //얻은 길이가 대기열 길이를 초과한 후 수정
  190. if ($length > $this- >LEN)
  191. $length = $this->LEN;
  192. $data = $this->popKeyArray($length);
  193. $this->unLock();
  194. $data 반환;
  195. }
  196. /*
  197. * 특정 길이의 값 팝
  198. * @param [length] int queue length
  199. * @return array
  200. */
  201. private function popKeyArray($length)
  202. {
  203. $result = array();
  204. if (empty($length))
  205. return $result;
  206. for ($k = 0 ; $k < $length; $k ) {
  207. $result[] = @memcache_get(self::$client, $this->queueName . self::VALU_KEY . $this->HEAD);
  208. @memcache_delete(self::$client, $this->queueName . self::VALU_KEY . $this->HEAD, 0);
  209. //값을 추출한 결과 head와 테일 오버랩(포인터가 이동하지 않은 경우), 오른쪽에 데이터가 없습니다. 즉, 큐의 마지막 데이터가 완전히 비워집니다. 이 때 포인터는 로컬로 유지되고 이동하지 않으며 큐는 길이는 0이 됩니다
  210. if ($this->TAIL == $this->HEAD && $this->LEN <= 1) {
  211. $this->LEN = 0;
  212. memcache_set(self::$client, $this->queueName . self ::LENGTH_KEY, $this->LEN, false, $this->expire) //업데이트
  213. break;
  214. } else {
  215. $this->incrHead(); //첫 번째와 마지막 중복이 없거나, 중복이 있지만 아직 읽지 않은 데이터가 있는 경우 읽을 다음 위치로 HEAD 포인터를 이동합니다.
  216. }
  217. }
  218. return $result;
  219. }
  220. /*
  221. * 대기열 재설정
  222. * * @return NULL
  223. */
  224. 개인 함수 재설정( $all = false)
  225. {
  226. if ($all ) {
  227. memcache_delete(self::$client, $this->queueName . self::HEAD_KEY, 0);
  228. memcache_delete(self::$client, $this->queueName . self::TAIL_KEY , 0);
  229. memcache_delete(self::$client, $this->queueName . self::LENGTH_KEY, 0);
  230. } else {
  231. $this->HEAD = $this-> ;TAIL = $this->LEN = 0;
  232. memcache_set(self::$client, $this->queueName . self ::HEAD_KEY, 0, false, $this->expire);
  233. memcache_set(self::$client, $this->queueName . self::TAIL_KEY, 0, false, $this->expire) ;
  234. memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, 0, false, $this->expire);
  235. }
  236. }
  237. /*
  238. * 모든 Memcache 캐시 데이터 지우기
  239. * @return NULL
  240. */
  241. 공용 함수 memFlush()
  242. {
  243. memcache_flush(self::$client);
  244. }
  245. 공용 함수 Clear($all = false)
  246. {
  247. if (!$this->lock())
  248. return false;
  249. $this- >getHeadAndTail();
  250. $Head = $this->HEAD;
  251. $Length = $this->LEN;
  252. $curr = 0;
  253. for ($i = 0; $i < $Length; $i ) {
  254. $curr = $this ->$Head $i;
  255. if ($curr >= $this->MAXNUM) {
  256. $this ->HEAD = $curr = 0;
  257. }
  258. @memcache_delete (self::$client, $this->queueName . self::VALU_KEY . $curr, 0);
  259. }
  260. $this->unLock();
  261. $this->reset($all);
  262. true를 반환합니다.
  263. }
  264. }
코드 복사


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.