解析php中curl_multi的应用


Posted in PHP onJuly 17, 2013

相信许多人对php手册中语焉不详的curl_multi一族的函数头疼不已,它们文档少,给的例子 更是简单的让你无从借鉴,我也曾经找了许多网页,都没见一个完整的应用例子。
•curl_multi_add_handle
•curl_multi_close
•curl_multi_exec
•curl_multi_getcontent
•curl_multi_info_read
•curl_multi_init
•curl_multi_remove_handle
•curl_multi_select
一般来说,想到要用这些函数时,目的显然应该是要同时请求多个url,而不是一个一个依次请求,否则不如自己循环去调curl_exec好了。

步骤总结如下:
第一步:调用curl_multi_init
第二步:循环调用curl_multi_add_handle
这一步需要注意的是,curl_multi_add_handle的第二个参数是由curl_init而来的子handle。
第三步:持续调用curl_multi_exec
第四步:根据需要循环调用curl_multi_getcontent获取结果
第五步:调用curl_multi_remove_handle,并为每个字handle调用curl_close
第六步:调用curl_multi_close

这里有一个网上找的简单例子,其作者称为dirty的例子,(稍后我会说明为何dirty):

*
Here's a quick and dirty example for curl-multi from PHP, tested on PHP 5.0.0RC1 CLI / FreeBSD 5.2.1
*/
$connomains = array(
"http://www.cnn.com/",
"http://www.canada.com/",
"http://www.yahoo.com/"
);
$mh = curl_multi_init();
foreach ($connomains as $i => $url) {
     $conn[$i]=curl_init($url);
      curl_setopt($conn[$i],CURLOPT_RETURNTRANSFER,1);
      curl_multi_add_handle ($mh,$conn[$i]);
}
do { $n=curl_multi_exec($mh,$active); } while ($active);
foreach ($connomains as $i => $url) {
      $res[$i]=curl_multi_getcontent($conn[$i]);
      curl_close($conn[$i]);
}
print_r($res);

整个使用过程差不多就是这样,但是,这个简单代码有个致命弱点,就是在do循环的那段,在整个url请求期间是个死循环,它会轻易导致CPU占用100%。

现在我们来改进它,这里要用到一个几乎没有任何文档的函数curl_multi_select了,虽然C的curl库对select有说明,但是,php里的接口和用法确与C中有不同。

把上面do的那段改成下面这样:

do {
                        $mrc = curl_multi_exec($mh,$active);
                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
                while ($active and $mrc == CURLM_OK) {
                        if (curl_multi_select($mh) != -1) {
                                do {
                                        $mrc = curl_multi_exec($mh, $active);
                                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
                        }
                }

因为$active要等全部url数据接受完毕才变成false,所以这里用到了curl_multi_exec的返回值判断是否还有数据,当有数据的时候就不停调用curl_multi_exec,暂时没有数据就进入select阶段,新数据一来就可以被唤醒继续执行。这里的好处就是CPU的无谓消耗没有了。

另外:还有一些细节的地方可能有时候要遇到:
控制每一个请求的超时时间,在curl_multi_add_handle之前通过curl_setopt去做:
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);

判断是否超时了或者其他错误,在curl_multi_getcontent之前用:curl_error($conn[$i]);

注意:php的multi_curl功能慎用,因为某些版本的curl和php的搭配有Bug。所以你调试过没问题的代码很可能在别的机器上不正确。

例如今天我发现在php5.2.2搭配curl/7.16.2版本如果CURLOPT_USERAGENT属性设置成某些值,则实际发送的HTTP头的会变成一串二进制值。

而恰好这个版本的php中strip_tags函数对含二进制的数据处理的不好,这才发现了这个Bug

PHP 相关文章推荐
PHP 一个页面执行时间类代码
Mar 05 PHP
PHP开发中的错误收集,不定期更新。
Feb 03 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十六)
Jun 30 PHP
php密码生成类实例
Sep 24 PHP
ThinkPHP结合AjaxFileUploader实现无刷新文件上传的方法
Oct 29 PHP
php自定义错误处理用法实例
Mar 20 PHP
PHP生成唯一订单号的方法汇总
Apr 16 PHP
thinkphp多层MVC用法分析
Dec 30 PHP
PHP会员找回密码功能的简单实现
Sep 05 PHP
PHP PDO操作MySQL基础教程
Jun 05 PHP
php array_chunk()函数用法与注意事项
Jul 12 PHP
PHP预定义接口――Iterator用法示例
Jun 05 PHP
php curl获取网页内容(IPV6下超时)的解决办法
Jul 16 #PHP
ie与session丢失(新窗口cookie丢失)实测及解决方案
Jul 15 #PHP
实测在class的function中include的文件中非php的global全局环境
Jul 15 #PHP
Php output buffering缓存及程序缓存深入解析
Jul 15 #PHP
PHP 转义使用详解
Jul 15 #PHP
thinkphp 一个页面使用2次分页的实现方法
Jul 15 #PHP
shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
Jul 15 #PHP
You might like
在PHP中运行Linux命令并启动SSH服务的例子
2014/06/12 PHP
PHP中Session和Cookie是如何操作的
2015/10/10 PHP
24条货真价实的PHP代码优化技巧
2016/07/28 PHP
ThinkPHP5框架缓存查询操作分析
2018/05/30 PHP
PHP时间戳和日期相互转换操作实例小结
2018/12/18 PHP
PHP实现创建一个RPC服务操作示例
2020/02/23 PHP
Alliance vs Liquid BO3 第二场2.13
2021/03/10 DOTA
jQuery UI AutoComplete 自动完成使用小记
2010/08/21 Javascript
关于火狐(firefox)及ie下event获取的两种方法
2012/12/27 Javascript
js的延迟执行问题分析
2014/06/23 Javascript
Node.js 制作实时多人游戏框架
2015/01/08 Javascript
基于jQuery创建鼠标悬停效果的方法
2015/03/07 Javascript
JavaScript中连接操作Oracle数据库实例
2015/04/02 Javascript
JS实现的页面自定义滚动条效果
2015/10/26 Javascript
ionic js 模型 $ionicModal 可以遮住用户主界面的内容框
2016/06/06 Javascript
url传递的参数值中包含&时,url自动截断问题的解决方法
2016/08/02 Javascript
Angular中使用$watch监听object属性值的变化(详解)
2017/04/24 Javascript
node.js读取Excel数据(下载图片)的方法示例
2018/08/02 Javascript
vue-cli3.0实现一个多页面应用的历奇经历记录总结
2020/03/16 Javascript
[52:22]EG vs VG Supermajor小组赛B组 BO3 第一场 6.2
2018/06/03 DOTA
在Gnumeric下使用Python脚本操作表格的教程
2015/04/14 Python
python dict.get()和dict['key']的区别详解
2016/06/30 Python
python 读写、创建 文件的方法(必看)
2016/09/12 Python
磁盘垃圾文件清理器python代码实现
2020/08/24 Python
详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?
2019/05/07 Python
PyQt5创建一个新窗口的实例
2019/06/20 Python
python opencv 读取图片 返回图片某像素点的b,g,r值的实现方法
2019/07/03 Python
python实现静态web服务器
2019/09/03 Python
python实现操作文件(文件夹)
2019/10/31 Python
用python解压分析jar包实例
2020/01/16 Python
三步解决python PermissionError: [WinError 5]拒绝访问的情况
2020/04/22 Python
Python 远程开关机的方法
2020/11/18 Python
街头时尚在线:JESSICABUURMAN
2019/06/16 全球购物
爱情保证书范文
2014/02/01 职场文书
公司庆典主持词
2015/07/04 职场文书
.Net Core导入千万级数据至Mysql的步骤
2021/05/24 MySQL