解析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 相关文章推荐
不用数据库的多用户文件自由上传投票系统(2)
Oct 09 PHP
用PHP和ACCESS写聊天室(九)
Oct 09 PHP
一个php Mysql类 可以参考学习熟悉下
Jun 21 PHP
php 安全过滤函数代码
May 07 PHP
php中批量删除Mysql中相同前缀的数据表的代码
Jul 01 PHP
php中将时间差转换为字符串提示的实现代码
Aug 08 PHP
关于PHP结束标签的使用细节探讨及联想
Mar 04 PHP
php将gd生成的图片缓存到memcache的小例子
Jun 05 PHP
使用php统计字符串中中英文字符的个数
Jun 23 PHP
PHP 双链表(SplDoublyLinkedList)简介和使用实例
May 12 PHP
非集成环境的php运行环境(Apache配置、Mysql)搭建安装图文教程
Apr 12 PHP
php中类和对象:静态属性、静态方法
Apr 09 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
[FAQ]PHP中的一些常识:类篇
2006/10/09 PHP
php 将字符串按大写字母分隔成字符串数组
2010/04/30 PHP
让Laravel API永远返回JSON格式响应的方法示例
2018/09/05 PHP
jQuery Lightbox 图片展示插件使用说明
2010/04/25 Javascript
jQuery使用动态渲染表单功能完成ajax文件下载
2013/01/15 Javascript
HTML5之lang属性与dir属性的详解
2013/06/19 Javascript
JS this作用域以及GET传输值过长的问题解决方法
2013/08/06 Javascript
JS正则验证邮箱的格式详细介绍
2013/11/19 Javascript
千分位数字格式化(用逗号隔开 代码已做了修改 支持0-9位逗号隔开)的JS代码
2013/12/05 Javascript
node.js中的fs.realpath方法使用说明
2014/12/16 Javascript
JavaScript插件化开发教程(五)
2015/02/01 Javascript
JS实现仿google、百度搜索框输入信息智能提示的实现方法
2015/04/20 Javascript
js控制div弹出层实现方法
2015/05/11 Javascript
JQuery实现动态添加删除评论的方法
2015/05/18 Javascript
jQuery插件windowScroll实现单屏滚动特效
2015/07/14 Javascript
JavaScript类继承及实例化的方法
2015/07/25 Javascript
js实现新年倒计时效果
2015/12/10 Javascript
javascript实现平滑无缝滚动
2020/08/09 Javascript
简单实现js鼠标跟随效果
2020/08/02 Javascript
[02:08]2014DOTA2国际邀请赛 430专访:力争取得小组前二
2014/07/11 DOTA
[34:39]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#1COL VS EG第二局
2016/03/05 DOTA
Python编程中实现迭代器的一些技巧小结
2016/06/21 Python
python itchat实现微信好友头像拼接图的示例代码
2017/08/14 Python
用Python实现随机森林算法的示例
2017/08/24 Python
python实现梯度下降算法
2020/03/24 Python
Python 面试中 8 个必考问题
2018/11/16 Python
Python面向对象封装操作案例详解 II
2020/01/02 Python
Python3 filecmp模块测试比较文件原理解析
2020/03/23 Python
印尼披萨外送专家:Domino’s Pizza印尼
2017/12/28 全球购物
伦敦著名的运动鞋综合商店:Footpatrol
2019/03/25 全球购物
澳大利亚体育和露营装备在线/实体零售商:Find Sports
2020/06/03 全球购物
PHP面试题及答案一
2012/06/18 面试题
挑战杯创业计划书的写作指南
2014/01/07 职场文书
给校长的一封建议书
2014/03/12 职场文书
2015年幼儿园学期工作总结
2015/05/22 职场文书
家访教师心得体会
2016/01/23 职场文书