解析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 高手之路(三)
Oct 09 PHP
php判断变量类型常用方法
Apr 24 PHP
PHP中使用sleep造成mysql读取失败的案例和解决方法
Aug 21 PHP
ecshop实现smtp发送邮件
Feb 03 PHP
php计算两个坐标(经度,纬度)之间距离的方法
Apr 17 PHP
php获取本周星期一具体日期的方法
Apr 20 PHP
超详细的php用户注册页面填写信息完整实例(附源码)
Nov 17 PHP
PHP信号量基本用法实例详解
Feb 12 PHP
php等比例缩放图片及剪切图片代码分享
Feb 13 PHP
PHP 芝麻信用接入的注意事项
Dec 01 PHP
PHP实现从上往下打印二叉树的方法
Jan 18 PHP
PHP面向对象程序设计之对象的遍历操作示例
Jun 12 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
使用Sphinx对索引进行搜索
2013/06/25 PHP
PHP全功能无变形图片裁剪操作类与用法示例
2017/01/10 PHP
[原创]php正则删除html代码中class样式属性的方法
2017/05/24 PHP
visual studio code 调试php方法(图文详解)
2017/09/15 PHP
基于swoole实现多人聊天室
2018/06/14 PHP
用Laravel轻松处理千万级数据的方法实现
2020/12/25 PHP
JavaScript中String和StringBuffer的速度之争
2010/04/01 Javascript
Javascript学习笔记 delete运算符
2011/09/13 Javascript
纯js分页代码(简洁实用)
2013/11/05 Javascript
JS过滤url参数特殊字符的实现方法
2013/12/24 Javascript
JS获取iframe中longdesc属性的方法
2015/04/01 Javascript
又一款js时钟!transform实现时钟效果
2016/08/15 Javascript
js格式化时间的简单实例
2016/11/27 Javascript
vue2.0获取自定义属性的值
2017/03/28 Javascript
深入浅析ES6 Class 中的 super 关键字
2017/10/20 Javascript
简述JS控制台的使用
2018/07/15 Javascript
JavaScript继承与聚合实例详解
2019/01/22 Javascript
微信小程序rich-text富文本用法实例分析
2019/05/20 Javascript
JS深入学习之数组对象排序操作示例
2020/05/01 Javascript
python中pycurl库的用法实例
2014/09/30 Python
跟老齐学Python之折腾一下目录
2014/10/24 Python
深入理解Javascript中的this关键字
2015/03/27 Python
Python如何获取系统iops示例代码
2016/09/06 Python
Python通过future处理并发问题
2017/10/17 Python
python Pandas 读取txt表格的实例
2018/04/29 Python
pip安装py_zipkin时提示的SSL问题对应
2018/12/29 Python
Python数据可视化 pyecharts实现各种统计图表过程详解
2019/08/15 Python
解决python多行注释引发缩进错误的问题
2019/08/23 Python
PyQT5 实现快捷键复制表格数据的方法示例
2020/06/19 Python
《孔子拜师》教学反思
2014/02/24 职场文书
公司经理任命书
2014/06/05 职场文书
会计专业毕业生自荐书
2014/06/25 职场文书
2014年技术工作总结范文
2014/11/20 职场文书
《巨人的花园》教学反思
2016/02/19 职场文书
详解MySQL数据库千万级数据查询和存储
2021/05/18 MySQL
聊聊配置 Nginx 访问与错误日志的问题
2022/05/25 Servers