目前的工作是需要对用户的一些数据进行分析,每个用户都有若干条记录,每条记录中有用户的一个位置,是用经度和纬度表示的。
还有一个给定的数据库,存储的是一些已知地点以及他们的经纬度,内有43W多条的数据。
现在需要拿用户的经纬度和已知地点进行距离匹配,如果它们之间的距离小于一定的数据,比如说500米,就认为用户是在这个地点。
MYSQL本身是支持空间索引的,但是在5.x的版本中,取消了对Distance()和Related()的支持,无法使用空间的距离函数去直接去查询距离在一定范围内的点。所以,我首先想到的是,对每条记录,去进行遍历,跟数据库中的每一个点进行距离计算,当距离小于500米时,认为匹配。这样做确实能够得到结果,但是效率极其低下,因为每条记录都要去循环匹配40W条数据,其消耗的时间可想而知。经过记录,发现每条记录处理的时间消耗达到1700ms,针对每天上亿的数据量,这样一个处理速度,让人情何以堪啊。。。
我自己也有个想法,就是找到每条记录所在点的经纬度周围的一个大概范围,比方说正方形的四个点,然后使用mysql的空间计算,使用MBR去得出点在这个矩形内的已知记录,然后进行匹配。可惜,自己没想出能计算到四个点经纬度的方法。
意外的,查询到了一个关于这个计算附近地点搜索初探,里面使用python实现了这个想法。
所以参考了一下原文中的算法,使用PHP进行了实现。
实现原理也是很相似的,先算出该点周围的矩形的四个点,然后使用经纬度去直接匹配数据库中的记录。
红色部分为要求的搜索范围,绿色部分我们能间接得到的结果范围
参考wiki百科上的一些球面计算公式:
Great-circle distance
Haversine formula
假设已知点的经纬度分别为$lng, $lat
先实现经度范围的查询,
在haversin公式中令φ1 = φ2,可得:
用PHP进行计算,就是:
Example
代码如下 | 复制代码 |
|
然后是纬度范围的查询,
在haversin公式中令 Δλ = 0,可得
在PHP中进行计算,就是:
Example
代码如下 | 复制代码 |
$dlat = $distance/EARTH_RADIUS;//EARTH_RADIUS地球半径 |
最后,就可以得出四个点的坐标:
left-top : (lat + dlat, lng – dlng)
right-top : (lat + dlat, lng + dlng)
left-bottom : (lat – dlat, lng – dlng)
right-bottom: (lat – dlat, lng + dlng)
我把以上方法写成了一个函数,综合起来就是:
Example
代码如下 | 复制代码 |
define(EARTH_RADIUS, 6371);//地球半径,平均半径为6371km $squares = returnSquarePoint($lng, $lat); |
在lat和lng上建立一个联合索引后,使用此项查询,每条记录的查询消耗平均为0.8毫秒,相比以前的1700ms,真的是天壤之别啊。效率真真的是以前的2125倍~~
总结:这应该也不是效率最好的办法,但是效率比以前确实有明显的提升。请记住,总有办法更好的。
HttpClient.class.php类是一个国外网站提供一个非常好用的HttpClient.class.php类了,我们可以利用它来做很多的事情,下面来看看通过HTTP协议客户端类HttpClient来介绍PHP POST HTTP请求的方法,这个类你可以到官方http://scripts.incutio.com/httpclient/index.php下载也可以通过本站下载点击下载附件
下载好后通过两个文件来测试下,新建一个PHP文件加入如下内容:
代码如下 | 复制代码 |
<?php |
上面代码第5行中的请求页面地址是receive.php所以再建一个receive.php文件,写入如下内容:
代码如下 | 复制代码 |
<?php echo "username:".$_POST['username']."<br/>"; echo "password:".$_POST['password']."<br/>"; ?> |
执行你建的第一个PHP文件将看到如下内容: username:guowenlong password:hahahaha
php中json是实时交换数据的一个常用的数据传输模式了,而serialize是把字符转换成一个序列化字符串了,那么它们两的性能那个会更好一些呢?对此小编整理了一些json和serialize 性能比较测试例子供各位学习参考。测试1
1,操作元素较少,单个元素比较大,英文,3个元素操作1000次
代码如下 | 复制代码 |
$data = array('hello','word'); $jsonen_sarttime = getmicrotime(); } $jsonde_starttime = getmicrotime(); echo "jsondecode耗时:".($jsonde_endtime - $jsonde_starttime)." $seri1_starttime = getmicrotime(); $seri2_starttime = getmicrotime(); echo "serialize反序列化耗时:".($seri2_endtime - $seri2_starttime)." /** |
output:
json长度:90019
jsonencode耗时:1.0974299907684
jsondecode耗时:1.6237480640411
serialize长度:90052
serialize序列化耗时:0.025779962539673
serialize反序列化耗时:0.029321193695068
可以看到json在做英文处理的时候,数组元素较少,体积要小于序列化的数据.处理效率低于序列化.
将data 更改为
代码如下 | 复制代码 |
$data = array('hello','word'); |
output:
json长度:120019
jsonencode耗时:0.83260488510132
jsondecode耗时:2.2054090499878
serialize长度:60052
serialize序列化耗时:0.01835298538208
serialize反序列化耗时:0.01848292350769
可以看到 json在做文字处理的时候,体积较大,处理效率也略低于序列化.
3.将数据更改为
代码如下 | 复制代码 |
$data = array('hello','word'); |
output:
json长度:150016
jsonencode耗时:2.1428198814392
jsondecode耗时:6.5845320224762
serialize长度:198939
serialize序列化耗时:2.8011980056763
serialize反序列化耗时:4.6967668533325
可以看到json体积略小于serialize
4.将data修改为
代码如下 | 复制代码 |
$data = array('hello','word'); |
output:
json长度:80016
jsonencode耗时:1.6437809467316
jsondecode耗时:4.5136170387268
serialize长度:188939
serialize序列化耗时:2.909558057785
serialize反序列化耗时:4.4678349494934
测试2
以一个包含1000000个元素的数组做为原始数据,分别以json, serialize, igbinary进行序列化和反向操作。
代码如下 | 复制代码 |
<?php $start = microtime(true); $start = microtime(true); $start = microtime(true); $start = microtime(true); $start = microtime(true); $start = microtime(true); |
测试结果
JSON Encode: 0.084825992584229
JSON Decode: 0.34976410865784
Serialize: 0.38241410255432
Serialize: 7.7904229164124
Igbinary Serialize: 0.046916007995605
Igbinary Serialize: 0.23396801948547
从测试结果来看,速度方面优先级排列为 igbinary > json > serialize。同时我们也可以看到,php原生的serialize在对大对象进行反向操作时,速度真是掉队一大截了。
占用字节数对比
json: 5000001
serialize: 15888902
igbinary: 7868681
在没有中文字符的情况下,json胜出,igbinary次之,serialize又被甩了几条街
结论,
如果只是英文和数字,元素比较平均,则推荐json,体积和效率均优于序列化
如果只是英文和数字,个别元素较大,则推荐serialize效率优于序列化
如果中文,元素较少,推荐序列化,体积和效率均优于json
如果中文,元素比较平均,推荐json
如果是缓存业务,效率越高越好,如果是缓存数据,体积越小越好。也要看具体的场景。
jQuery Mobile是jQuery 在手机上和平板设备上的版本。jQuery Mobile 不仅会给主流移动平台带来jQuery核心库,而且会发布一个完整统一的jQuery移动UI框架。现在我们来讲讲jQuery Mobile + php在手机上上传图片的实例。很简单的一个小例子 jQuery Mobile + PHP 通过超全局 $_FILES 上传,然后用move_uploaded_file()方法把上传的图片移动到到本地服务器下的文件夹,
下面是html代码
代码如下 | 复制代码 |
<!DOCTYPE html> <html> <head> <meta charset = "utf-8"> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.css"> <script" width=100% src="http://code.jquery.com/jquery-1.8.3.min.js"></script> <script" width=100% src="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script> </head> <body> <div data-role="page" id="upload" > <div data-role="header" > <h1>校园祭</h1> <a href="#pageone" data-rolr = button data-icon="home" class="ui-btn-left" >首页</a> </div> <div data-role="content" > <form action="upload_file.php" method="post" enctype="multipart/form-data" data-ajax="false"> <input id="uploadimg" name="file" type="file" runat="server" method="post" enctype="multipart/form-data" data-inline="true" data-ajax="false" /> <center><button data-inline="true" >上传</button></center> </form> </div> <div data-role="footer" data-position="fixed" data-fullscreen="true"> <h1>创新实验</h1> </div> </div> </body> </html> |
php的代码
代码如下 | 复制代码 |
<?php if ($_FILES["file"]["error"] > 0) { echo "Return Code: " . $_FILES["file"]["error"] . "<br />"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br />"; echo "Type: " . $_FILES["file"]["type"] . "<br />"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />"; echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />"; if (file_exists("upload/" . $_FILES["file"]["name"])) { echo $_FILES["file"]["name"] . " already exists. "; } else { move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]); echo "Stored in: " ."upload/". $_FILES["file"]["name"]; } } } ?> |
代码很简单,但是使用过程中却发现一个问题,自己试了好久都上传不了。询问了小伙伴后,发现问题所在是文件权限不足,从而限制了网页上传图片到文件夹中.所以解决办法就是把文件夹的权限问题解决掉.
代码如下 | 复制代码 |
$ cd /var/www $ sudo chmod -R 777 html |
ok,现在就可以将文件上传到服务器的文件夹了.
pcntl_fork()函数创建一个子进程,这个子进程仅PID(进程号) 和PPID(父进程号)与其父进程不同。fork怎样在您的系统工作的详细信息请查阅您的系统 的fork(2)手册。
注意:PHP有个pcntl_fork的函数可以实现多进程,但要加载pcntl拓展,而且只有在linux下才能编译这个拓展.
1.首先在ubuntu下编译pcntl.so,我的ubuntu下找不到pcntl的包,于是创建一个文件夹下载了整个PHP包,在里面找到了pcntl包运行如下命令,代码如下:
代码如下 | 复制代码 |
# mkdir php # cd php # apt-get source php5 # cd php5-(WHATEVER_RELEASE)/ext/pcntl # phpize # ./configure (注一) # make # make install phpize 命令是用来准备 PHP 外挂模块的编译环境的 |
成功的安装将建立 extname.so 并放置于 PHP 的外挂模块目录中(预设存放于 /usr/lib/php/modules/ 内),需要调整 php.ini,加入 extension=extname.so 这一行之后才能使用此外挂模块.
代码如下 | 复制代码 |
void pcntl_exec(string $path [,array $args [,array $envs ]])
pcntl_exec — 在当前进程空间执行指定程序,代码如下: $cmds=array( |
例,实例多图片同步下载,代码如下:
代码如下 | 复制代码 |
#!/usr/bin/php <?php // 需要抓取的网页地址 $url = 'http://www.jb51.net'; $content = file_get_contents($url); preg_match_all('/<imgs+src="(.*?)"/', $content, $matches,PREG_SET_ORDER); echo "已发现".count($matches)."张图片n"; list($sm, $ss) = explode(" ", microtime()); foreach ($matches as $k => $val) { $pid[$k] = pcntl_fork(); if(!$pid[$k]) { download($url, $val); // 子进程要exit否则会进行递归多进程,父进程不要exit否则终止多进程 exit(0); } if ($pid[$k]) { // pcntl_waitpid($pid[$k], $status, WUNTRACED); } } echo "下载完成n"; list($em, $es) = explode(" ", microtime()); echo "用时:",($es+$em) - ($ss + $sm),"n"; /** * 抓取网页图片 * */ function download($url, $val) { $pic_url = $val[1]; if (strpos($val[1], '//') !== false) { ; } elseif (preg_match('@^(.*?)/@', $val[1], $inner_matches) == 0) { $pic_url = $url.$val[1]; } elseif (preg_match('@[:.]@', $inner_matches[1], $tmp_matches) == 0) { $pic_url = $url.$val[1]; } $pic = file_get_contents($pic_url); if ($pic === false) { return; } preg_match('@/([^/]+)$@', $pic_url, $tmp_matches); // 可使用assert处理异常 $pic_file_name = $tmp_matches[1]; $f = fopen("tmp/".$pic_file_name, "wb"); # fwrite($f, $pic); fclose($f); } /* End of file pcntl_fork.php */ ?> |
多进程同步下载图片是一个非常有用的技术,希望本教程对你有所帮助。