解析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巧获服务器端信息
Dec 06 PHP
利用PHP制作简单的内容采集器的代码
Nov 28 PHP
PHP执行linux系统命令的常用函数使用说明
Apr 27 PHP
基于curl数据采集之单页面并行采集函数get_htmls的使用
Apr 28 PHP
深入解析Session是否必须依赖Cookie
Aug 02 PHP
php基于Fleaphp框架实现cvs数据导入MySQL的方法
Feb 23 PHP
Joomla实现组件中弹出一个模式(modal)窗口的方法
May 04 PHP
php使用parse_str实现查询字符串解析到变量中的方法
Feb 17 PHP
PHP缓存工具XCache安装与使用方法详解
Apr 09 PHP
postman的安装与使用方法(模拟Get和Post请求)
Aug 06 PHP
PHP设计模式之PHP迭代器模式讲解
Mar 22 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利用单例模式实现日志处理类库
2014/02/10 PHP
Mac系统下使用brew搭建PHP(LNMP/LAMP)开发环境
2015/03/03 PHP
PHP中实现Bloom Filter算法
2015/03/30 PHP
PHP多种序列化/反序列化的方法详解
2017/06/23 PHP
让 JavaScript 轻松支持函数重载 (Part 2 - 实现)
2009/08/04 Javascript
javascript测试题练习代码
2012/10/10 Javascript
jQuery拖动div、移动div、弹出层实现原理及示例
2014/04/08 Javascript
JQuery通过AJAX从后台获取信息显示在表格上并支持行选中
2015/09/15 Javascript
JavaScript实现的鼠标响应颜色渐变效果完整实例
2017/02/18 Javascript
node.js 核心http模块,起一个服务器,返回一个页面的实例
2017/09/11 Javascript
webpack+react+antd脚手架优化的方法
2018/04/02 Javascript
详解Nodejs内存治理
2018/05/13 NodeJs
Vue的watch和computed方法的使用及区别介绍
2018/09/06 Javascript
vue项目强制清除页面缓存的例子
2019/11/06 Javascript
[02:57]2014DOTA2国际邀请赛 选手辛苦解说更辛苦
2014/07/10 DOTA
[40:16]TFT vs Mski Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
Python中字典和JSON互转操作实例
2015/01/19 Python
Python实现统计文本文件字数的方法
2017/05/05 Python
Python爬虫之xlml解析库(全面了解)
2017/08/08 Python
如何更优雅地写python代码
2019/07/02 Python
如何不用安装python就能在.NET里调用Python库
2019/07/12 Python
关于win10在tensorflow的安装及在pycharm中运行步骤详解
2020/03/16 Python
Django 实现对已存在的model进行更改
2020/03/28 Python
解决Django no such table: django_session的问题
2020/04/07 Python
大学生实习自我鉴定
2013/12/11 职场文书
售后服务承诺书模板
2014/05/21 职场文书
党章培训心得体会
2014/09/04 职场文书
2014年大学生社会实践自我鉴定
2014/09/26 职场文书
采购内勤岗位职责
2015/04/13 职场文书
青涩记忆观后感
2015/06/18 职场文书
暑假生活随笔
2015/08/15 职场文书
MySQL 8.0 之不可见列的基本操作
2021/05/20 MySQL
Python编程根据字典列表相同键的值进行合并
2021/10/05 Python
WebWorker 封装 JavaScript 沙箱详情
2021/11/02 Javascript
mysql5.6主从搭建以及不同步问题详解
2021/12/04 MySQL
Redis实现一个账号只能登录一个设备
2022/04/19 Redis