PHP memcache实现消息队列实例
memche消息队列的原理就是在key上做文章,用以做一个连续的数字加上前缀记录序列化以后消息或者日志。然后通过定时程序将内容落地到文件或者数据库。
php实现消息队列的用处比如在做发送邮件时发送大量邮件很费时间的问题,那么可以采取队列。
方便实现队列的轻量级队列服务器是:
starling支持memcache协议的轻量级持久化服务器
https://github.com/starling/starling
Beanstalkd轻量、高效,支持持久化,每秒可处理3000左右的队列
http://kr.github.com/beanstalkd/
php中也可以使用memcache/memcached来实现消息队列。
代码如下 | 复制代码 |
<?php class QMC { /** /** |
基于PHP共享内存实现的消息队列:
代码如下 | 复制代码 |
<?php private $front = 0; // 队头指针 private $blockSize = 256; // 块的大小(byte) private $filePtr = './shmq.ptr'; private $semId = 0; $this->shmId = shmop_open($shmkey, "c", 0644, $this->memSize ); // 申?一个信号量 $this->init(); private function init() public function getLength() public function enQueue( $value ) $data = $this->encode($value); public function deQueue() private function ptrInc( $ptr ) private function encode( $value ) echo strlen($data); echo $this->blockSize -1; if ( strlen($data) > $this->blockSize -1 ){ private function decode( $value ) public function __destruct() sem_release($this->semId); // 出临界区, 释放信号量 /* |
对于一个很大的消息队列,频繁进行进行大数据库的序列化 和 反序列化,有太耗费。下面是我用PHP 实现的一个消息队列,只需要在尾部插入一个数据,就操作尾部,不用操作整个消息队列进行读取,与操作。但是,这个消息队列不是线程安全的,我只是尽量的避免了冲突的可能性。如果消息不是非常的密集,比如几秒钟才一个,还是可以考虑这样使用的。
如果你要实现线程安全的,一个建议是通过文件进行锁定,然后进行操作。下面是代码:
代码如下:
代码如下 | 复制代码 |
class Memcache_Queue { private $memcache; private $name; private $prefix; function __construct($maxSize, $name, $memcache, $prefix = "__memcache_queue__") { if ($memcache == null) { throw new Exception("memcache object is null, new the object first."); } $this->memcache = $memcache; $this->name = $name; $this->prefix = $prefix; $this->maxSize = $maxSize; $this->front = 0; $this->real = 0; $this->size = 0; } function __get($name) { return $this->get($name); } function __set($name, $value) { $this->add($name, $value); return $this; } function isEmpty() { return $this->size == 0; } function isFull() { return $this->size == $this->maxSize; } function enQueue($data) { if ($this->isFull()) { throw new Exception("Queue is Full"); } $this->increment("size"); $this->set($this->real, $data); $this->set("real", ($this->real + 1) % $this->maxSize); return $this; } function deQueue() { if ($this->isEmpty()) { throw new Exception("Queue is Empty"); } $this->decrement("size"); $this->delete($this->front); $this->set("front", ($this->front + 1) % $this->maxSize); return $this; } function getTop() { return $this->get($this->front); } function getAll() { return $this->getPage(); } function getPage($offset = 0, $limit = 0) { if ($this->isEmpty() || $this->size < $offset) { return null; } $keys[] = $this->getKeyByPos(($this->front + $offset) % $this->maxSize); $num = 1; for ($pos = ($this->front + $offset + 1) % $this->maxSize; $pos != $this->real; $pos = ($pos + 1) % $this->maxSize) { $keys[] = $this->getKeyByPos($pos); $num++; if ($limit > 0 && $limit == $num) { break; } } return array_values($this->memcache->get($keys)); } function makeEmpty() { $keys = $this->getAllKeys(); foreach ($keys as $value) { $this->delete($value); } $this->delete("real"); $this->delete("front"); $this->delete("size"); $this->delete("maxSize"); } private function getAllKeys() { if ($this->isEmpty()) { return array(); } $keys[] = $this->getKeyByPos($this->front); for ($pos = ($this->front + 1) % $this->maxSize; $pos != $this->real; $pos = ($pos + 1) % $this->maxSize) { $keys[] = $this->getKeyByPos($pos); } return $keys; } private function add($pos, $data) { $this->memcache->add($this->getKeyByPos($pos), $data); return $this; } private function increment($pos) { return $this->memcache->increment($this->getKeyByPos($pos)); } private function decrement($pos) { $this->memcache->decrement($this->getKeyByPos($pos)); } private function set($pos, $data) { $this->memcache->set($this->getKeyByPos($pos), $data); return $this; } private function get($pos) { return $this->memcache->get($this->getKeyByPos($pos)); } private function delete($pos) { return $this->memcache->delete($this->getKeyByPos($pos)); } private function getKeyByPos($pos) { return $this->prefix . $this->name . $pos; } } |
php 5.3之前使用的垃圾回收机制是单纯的“引用计数”,也就是每个内存对象都分配一个计数器,当内存对象被变量引用时,计数器 1;当变量引用撤掉后,计数器-1;当计数器=0时,表明内存对象没有被使用,该内存对象则进行销毁,垃圾回收完成。
“引用计数”存在问题,就是当两个或多个对象互相引用形成环状后,内存对象的计数器则不会消减为0;这时候,这一组内存对象已经没用了,但是不能回收,从而导致内存泄露;
php5.3开始,使用了新的垃圾回收机制,在引用计数基础上,实现了一种复杂的算法,来检测内存对象中引用环的存在,以避免内存泄露。
该算法可以参考下面这篇文章,这是这篇小总结的主要参考文献:) :浅谈PHP5中垃圾回收算法(Garbage Collection)的演化
看下面的例子
Example 1: gc.php
代码如下 | 复制代码 |
<?php echo $b ."n"; 不用说 % php -f gc.php 输出结果非常明了: |
好,下一个:
Example 2:
代码如下 | 复制代码 |
<?php $b = 'I will change?'; echo $a ."n"; |
君请看:
Example 3:
代码如下 | 复制代码 |
<?php unset($a); echo $a ."n"; |
有点犯迷糊了吗?
君再看:
Example 4:
代码如下 | 复制代码 |
<?php unset($b); echo $a ."n"; |
其实如果 Example 3 理解了,这个与之异曲同工.
hy0kl% php -f gc.php
I am test.
Notice: Undefined variable: b in /usr/local/www/apache22/data/test/gc.php on line 9
君且看:
Example 5:
代码如下 | 复制代码 |
<?php $a = null; echo '$a = '. $a ."n"; |
'$b = '. $b ."n";
?>
猛的第一感觉是什么样的?
hy0kl% php -f gc.php
$a =
$b =
没错,这就是输出结果,对 PHP GC 已有深入理解的 phper 不会觉得有什么奇怪,说实话,当我第一次运行这段代码时很意外,却让我对 PHP GC 有更深刻的理解了.那么下面与之同工的例子自然好理解了.
Example 6:
代码如下 | 复制代码 |
<?php $b = null; echo '$a = '. $a ."n"; |
这是一篇的php教程了,大家还可以百度去了解更多关于PHP垃圾回收机制文章哦,这里就不一一介绍了。
本文章给各位同学介绍分享淘宝API辅助函数-适用CI框架,有需要了解的朋友可参考。最近在重写一个淘宝客的网站,考虑到以后的拓展性,所以把它整合进CI里面了,这就出现个问题了,淘宝的SDK怎么整合进类库呢?仔细阅读淘宝API文档后,发现一个非SDK调用方法,我在这基础上加以修改整合成CI的helper函数,现在把源码分享给大家,希望帮到有需要的同学。
调用方法很简单,传入一个数组参数,其中method是你打算调用的API接口,其余的参数根据API接口的实际需要填入。我这里给个调用例子给大家看下。
代码如下 | 复制代码 |
|
主要是考虑到QQ的PHP SDK写的真是太烂了,纯属是普及API知识,而不是到手就可以部署的类库。。反正自己都写了一个了,就拿出来分享下。。
什么也不多说,直接上代码。
Qq_sdk.php
代码如下 | 复制代码 |
<?php /** * QQ开发平台 SDK * 作者:偶尔陶醉 * blog: www.stutostu.com */
class Qq_sdk{
//配置APP参数 private $app_id = 你的APP ID; private $app_secret = ‘你的APP_secret’; private $redirect = 你的回调地址;
function __construct() {
}
/** * [get_access_token 获取access_token] * @param [string] $code [登陆后返回的$_GET['code']] * @return [array] [expires_in 为有效时间 , access_token 为授权码 ; 失败返回 error , error_description ] */ function get_access_token($code) { //获取access_token $token_url = ‘https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&’ . ‘client_id=’ . $this->app_id . ‘&redirect_uri=’ . urlencode($this->redirect)//回调地址 . ‘&client_secret=’ . $this->app_secret . ‘&code=’ . $code; $token = array(); //expires_in 为access_token 有效时间增量 parse_str($this->_curl_get_content($token_url), $token);
return $token; }
/** * [get_open_id 获取用户唯一ID,openid] * @param [string] $token [授权码] * @return [array] [成功返回client_id 和 openid ;失败返回error 和 error_msg] */ function get_open_id($token) { $str = $this->_curl_get_content(‘https://graph.qq.com/oauth2.0/me?access_token=’ . $token); if (strpos($str, “callback”) !== false) { $lpos = strpos($str, “(“); $rpos = strrpos($str, “)”); $str = substr($str, $lpos + 1, $rpos – $lpos -1); } $user = json_decode($str, TRUE);
return $user; }
/** * [get_user_info 获取用户信息] * @param [string] $token [授权码] * @param [string] $open_id [用户唯一ID] * @return [array] [ret:返回码,为0时成功。msg为错误信息,正确返回时为空。...params] */ function get_user_info($token, $open_id) {
//组装URL $user_info_url = ‘https://graph.qq.com/user/get_use . ‘access_token=’ . $token . ‘&oauth_consumer_key=’ . $this->app_id . ‘&openid=’ . $open_id . ‘&format=json’;
$info = json_decode($this->_curl_get_content($user_info_url), TRUE);
return $info; }
private function _curl_get_content($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_URL, $url); //设置超时时间为3s curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 3); $result = curl_exec($ch); curl_close($ch);
return $result; }
}
/* end of Qq_sdk.php */
|
使用方法:在你网站上放置超链接,地址为:https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=你的APP_ID&redirect_uri=你的回调地址
在回调地址上调用我上面这个qq_sdk即可。
demo如下:
代码如下 | 复制代码 |
if(empty($_GET['code'])) { exit(‘参数非法’); }
include(‘qq_sdk’); $qq_sdk = new Qq_sdk(); $token = $qq_sdk->get_access_token($_GET['code']); print_r($token);
$open_id = $qq_sdk->get_open_id($token['access_token']); print_r($open_id);
$user_info = $qq_sdk->get_user_info($token['access_token'], $open_id['openid']); print_r($user_info); |
识别图片主色调这个,网上貌似有几种方法,不过,最准确,最优雅的解决方案还是利用聚类算法来做。。。
直接上代码。。。。不过,我测试结果表示,用PHP来做,效率不佳,PHP不适合做这种大规模运算~~~,用nodejs做 效率可以高出100倍左右。。。
代码如下 | 复制代码 |
<?php $start = microtime(TRUE); main();
function main($img = ‘colors_files/T1OX3eXldXXXcqfYM._111424.jpg’) {
list($width, $height, $mime_code) = getimagesize($img);
$im = null; $point = array(); switch ($mime_code) { # jpg case 2: $im =imagecreatefromjpeg($img); break;
# png case 3:
default: exit(‘擦 ,什么图像?解析不了啊’); }
$new_width = 100; $new_height = 100; $pixel = imagecreatetruecolor($new_width, $new_height); imagecopyresampled($pixel, $im, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
run_time();
$i = $new_width; while ($i–) { # reset高度 $k = $new_height; while ($k–) { $rgb = ImageColorAt($im, $i, $k); array_push($point, array(‘r’=>($rgb >> 16) & 0xFF, ‘g’=>($rgb >> 8) & 0xFF, ‘b’=>$rgb & 0xFF)); } } imagedestroy($im); imagedestroy($pixel);
run_time();
$color = kmeans($point);
run_time();
foreach ($color as $key => $value) &nb echo ‘<br><span style=“background-color:’ . RGBToHex($value[0]) . ‘” >’ . RGBToHex($value[0]) . ‘</span>’; }
}
function run_time() { global $start; echo ‘<br/>消耗:’, microtime(TRUE) – $start; }
function kmeans($point=array(), $k=3, $min_diff=1) { global $ii; $point_len = count($point); $clusters = array(); $cache = array();
for ($i=0; $i < 256; $i++) { $cache[$i] = $i*$i; }
# 随机生成k值 $i = $k; $index = 0; while ($i–) { $index = mt_rand(1,$point_len-100); array_push($clusters, array($point[$index], array($point[$index]))); }
run_time(); $point_list = array();
$run_num = 0;
while (TRUE) { foreach ($point as $value) { $smallest_distance = 10000000;
# 求出距离最小的点 # index用于保存point最靠近的k值 $index = 0; $i = $k; while ($i–) { $distance = 0; foreach ($value as $key => $p1) { &n { $distance += $cache[$p1 - $clusters[$i][0][$key]]; } else { $distance += $cache[$clusters[$i][0][$key] – $p1]; } }
$ii++;
if ($distance < $smallest_distance) { $smallest_distance = $distance; $index = $i; } } $point_list[$index][] = $value; }
$diff = 0; # 1个1个迭代k值 $i = $k; while ($i–) { $old = $clusters[$i];
# 移到到队列中心 $center = calculateCenter($point_list[$i], 3); # 形成新的k值集合队列 $new_cluster = array($center, $point_list[$i]); $clusters[$i] = $new_cluster;
# 计算新的k值与队列所在点的位置 $diff = euclidean($old[0], $center); }
# 判断是否已足够聚合 if ($diff < $min_diff) { break; }
} echo ‘—>’.$ii;
return $clusters; }
# 计算2点距离 $ii = 0; function euclidean($p1, $p2) {
$s = 0; foreach ($p1 as $key => $value) {
$temp = ($value – $p2[$key]); $s += $temp*$temp; }
return sqrt($s);
}
# 移动k值到所有点的中心 function calculateCenter($point_list, $attr_num) { $vals = array(); $point_num = 0;
$keys = array_keys($point_list[0]); foreach($keys as $value) { $vals[$value] = 0; }
foreach ($point_list as $arr) { $point_num++; foreach ($arr as $key => $value) { $vals[$key] += $value; } }
foreach ($keys as $index) { $vals[$index] = $vals[$index] / $point_num; }
return $vals; }
function RGBToHex($r, $g=”, $b=”) { if (is_array($r)) { $b = $r['b']; $g = $r['g'];
}
$hex = “#”; $hex.= str_pad(dechex($r), 2, ’0′, STR_PAD_LEFT); $hex.= str_pad(dechex($g), 2, ’0′, STR_PAD_LEFT); $hex.= str_pad(dechex($b), 2, ’0′, STR_PAD_LEFT);
return $hex; } ?> |
相关文章
- php语言实现redis的客户端与服务端有一些区别了因为前面介绍过服务端了这里我们来介绍客户端吧,希望文章对各位有帮助。 为了更好的了解redis协议,我们用php来实现...2016-11-25
- 有时我们在页面上需要选择数值范围,如购物时选取价格区间,购买主机时自主选取CPU,内存大小配置等,使用直观的滑块条直接选取想要的数值大小即可,无需手动输入数值,操作简单又方便。HTML首先载入jQuery库文件以及jRange相关...2015-03-15
- 本文实例讲述了JS实现的简洁纵向滑动菜单(滑动门)效果。分享给大家供大家参考,具体如下:这是一款纵向布局的CSS+JavaScript滑动门代码,相当简洁的手法来实现,如果对颜色不满意,你可以试着自己修改CSS代码,这个滑动门将每一...2015-10-21
- 队列的特性很简答,就是先进先出,一般利用数组来实现,本文就介绍了C#队列的简单使用,文中根据实例编码详细介绍的十分详尽,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-17
- 这篇文章主要介绍了SpringBoot集成Redis实现消息队列的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
jQuery+slidereveal实现的面板滑动侧边展出效果
我们借助一款jQuery插件:slidereveal.js,可以使用它控制面板左右侧滑出与隐藏等效果,项目地址:https://github.com/nnattawat/slideReveal。如何使用首先在页面中加载jquery库文件和slidereveal.js插件。复制代码 代码如...2015-03-15- 翻板抽奖的实现流程:前端页面提供6个方块,用数字1-6依次表示6个不同的方块,当抽奖者点击6个方块中的某一块时,方块翻转到背面,显示抽奖中奖信息。看似简单的一个操作过程,却包含着WEB技术的很多知识面,所以本文的读者应该熟...2015-10-21
SQLMAP结合Meterpreter实现注入渗透返回shell
sqlmap 是一个自动SQL 射入工具。它是可胜任执行一个广泛的数据库管理系统后端指印, 检索遥远的DBMS 数据库等,下面我们来看一个学习例子。 自己搭建一个PHP+MYSQ...2016-11-25PHP分布式框架如何使用Memcache同步SESSION教程
本教程主要讲解PHP项目如何用实现memcache分布式,配置使用memcache存储session数据,以及memcache的SESSION数据如何同步。 至于Memcache的安装配置,我们就不讲了,以前...2016-11-25- 复制代码 代码如下: // 第一种写法 $da = date("w"); if( $da == "1" ){ echo "今天是星期一"; }else if( $da == "2" ){ echo "今天是星期二"; }else if( $da == "3" ){ echo "今天是星期三"; }else if( $da == "4"...2013-10-04
- js里面设置DOM节点透明度的函数属性:filter= "alpha(opacity=" + value+ ")"(兼容ie)和opacity=value/100(兼容FF和GG)。 先来看看设置透明度的兼容性代码: 复制代码 代码如下: function setOpacity(ele, opacity) { if (...2014-06-07
- 这篇文章主要介绍了c++优先队列(priority_queue)用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
C#使用RabbitMq队列(Sample,Work,Fanout,Direct等模式的简单使用)
这篇文章主要介绍了C#使用RabbitMq队列(Sample,Work,Fanout,Direct等模式的简单使用),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-12-08- memche消息队列的原理就是在key上做文章,用以做一个连续的数字加上前缀记录序列化以后消息或者日志。然后通过定时程序将内容落地到文件或者数据库。php实现消息队列的用处比如在做发送邮件时发送大量邮件很费时间的问...2014-05-31
- 本文我们需要解决的问题是如何实现Http请求来实现通信,解决Android 2.3 版本以后无法使用Http请求问题,下面请看正文。 Android开发中使用HttpClient来开发Http程序...2016-09-20
- 这篇文章主要介绍了Nodejs 数组的队列以及forEach的应用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25
asp.net通过消息队列处理高并发请求(以抢小米手机为例)
这篇文章主要介绍了asp.net通过消息队列处理高并发请求(以抢小米手机为例),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22- 这篇文章主要介绍了C#队列Queue用法,实例分析了队列的功能、定义及相关使用技巧,需要的朋友可以参考下...2020-06-25
- 本篇文章小编为大家介绍,基于条件变量的消息队列 说明介绍。需要的朋友参考一下...2020-04-25
- 复制代码 代码如下:call PROCEDURE_split('分享,代码,片段',',');select * from splittable;复制代码 代码如下:drop PROCEDURE if exists procedure_split;CREATE PROCEDURE `procedure_split`( inputstring varc...2014-05-31