解析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 相关文章推荐
最省空间的计数器
Oct 09 PHP
Discuz!5的PHP代码高亮显示插件(黑暗中的舞者更新)
Jan 29 PHP
php 执行系统命令的方法
Jul 07 PHP
php警告Creating default object from empty value 问题的解决方法
Apr 02 PHP
PHP统计当前在线用户数实例讲解
Oct 21 PHP
PHP远程调试之XDEBUG
Dec 29 PHP
php使用get_class_methods()函数获取分类的方法
Jul 20 PHP
Thinkphp框架开发移动端接口(1)
Aug 18 PHP
Thinkphp框架中D方法与M方法的区别
Dec 23 PHP
PHP实现蛇形矩阵,回环矩阵及数字螺旋矩阵的方法分析
May 29 PHP
Laravel框架中VerifyCsrfToken报错问题的解决
Aug 30 PHP
php5.6.x到php7.0.x特性小结
Aug 17 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 用数组降低程序的时间复杂度
2009/12/04 PHP
PHP+Mysql树型结构(无限分类)数据库设计的2种方式实例
2014/07/15 PHP
php中strtotime函数性能分析
2016/11/20 PHP
jquery动画2.元素坐标动画效果(创建一个图片走廊)
2012/08/24 Javascript
JAVASCRIPT函数作用域和提前声明 分享
2013/08/22 Javascript
jquery获取所有选中的checkbox实现代码
2016/05/26 Javascript
vuex实现简易计数器
2016/10/27 Javascript
jQuery实现背景滑动菜单
2016/12/02 Javascript
关于angular js_$watch监控属性和对象详解
2017/04/24 Javascript
bootstrap table单元格新增行并编辑
2017/05/19 Javascript
解决jQuery ajax动态新增节点无法触发点击事件的问题
2017/05/24 jQuery
详解Vue单元测试Karma+Mocha学习笔记
2018/01/31 Javascript
js将URL网址转为16进制加密与解密函数
2020/03/04 Javascript
[05:53]完美世界携手游戏风云打造 卡尔工作室观战系统篇
2013/04/22 DOTA
Python生成不重复随机值的方法
2015/05/11 Python
Python中threading模块join函数用法实例分析
2015/06/04 Python
Python使用bs4获取58同城城市分类的方法
2015/07/08 Python
用Python解决x的n次方问题
2019/02/08 Python
Django使用Channels实现WebSocket的方法
2019/07/28 Python
linux centos 7.x 安装 python3.x 替换 python2.x的过程解析
2020/12/14 Python
关于HTML5 Placeholder新标签低版本浏览器下不兼容的问题分析及解决办法
2016/01/27 HTML / CSS
法国在线宠物店:zooplus.fr
2018/02/23 全球购物
shell变量的作用空间是什么
2013/08/17 面试题
音乐系毕业生自荐信
2013/10/27 职场文书
项目经理岗位职责
2013/11/11 职场文书
个人实习生的自我评价
2014/02/16 职场文书
房地产广告策划方案
2014/05/15 职场文书
中文专业自荐书
2014/06/29 职场文书
积极心理学课程心得体会
2016/01/22 职场文书
pytorch通过训练结果的复现设置随机种子
2021/06/01 Python
日本十大血腥动漫,那些被禁播的动漫盘点
2022/03/21 日漫
剧场版《转生恶役只好拔除破灭旗标》公开最新视觉图 2023年上映
2022/04/02 日漫
JAVA长虹键法之建造者Builder模式实现
2022/04/10 Java/Android
我家女友可不止可爱呢 公开OP主题曲无字幕动画MV
2022/04/11 日漫
Elasticsearch 数据类型及管理
2022/04/19 Python
Python可视化神器pyecharts绘制地理图表
2022/07/07 Python