利用curl 多线程 模拟 并发的详解


Posted in PHP onJune 14, 2013

首先,先了解下 php中的curl多线程函数:

# 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]);

这里我只是简单使用上述的dirty的例子(足够用了,并未发现cpu使用100%的情况)。
对“看点”(kandian.com)某一接口模拟并发,功能是向 memcache中读数据并写入数据。因为保密关系,相关数据及结果就不贴出了。

模拟了3次,第一次10线程同时请求1000次,第二次,100线程同时请求1000次,第三次,1000线程同时请求100次(已经相当费劲了,不敢在设置超过1000的多线程)。
看来curl多线程模拟并发还是有一定局限的。

另外还怀疑,可能会因为多线程延迟带来结果的大误差,对比数据发现。在初始化和set所用时间出入不大,差别处在get方法,因此可简单排除这点~~~

 

PHP 相关文章推荐
php 显示指定路径下的图片
Oct 29 PHP
php实现网站插件机制的方法
Nov 10 PHP
PHP 根据IP地址控制访问的代码
Apr 22 PHP
PHP 第二节 数据类型之转换
Apr 28 PHP
PHP echo,print,printf,sprintf函数之间的区别与用法详解
Nov 27 PHP
PHP错误Cannot use object of type stdClass as array in错误的解决办法
Jun 12 PHP
网站防止被刷票的一些思路与方法
Jan 08 PHP
既简单又安全的PHP验证码 附调用方法
Jun 02 PHP
php操作路径的经典方法(必看篇)
Oct 04 PHP
PHP基于curl模拟post提交json数据示例
Jun 22 PHP
PHP命名空间简单用法示例
Dec 28 PHP
php的优点总结 php有哪些优点
Jul 19 PHP
修改php.ini不生效问题解决方法(上传大于8M的文件)
Jun 14 #PHP
与文件上传有关的php配置参数总结
Jun 14 #PHP
解决File size limit exceeded 错误的方法
Jun 14 #PHP
使用PHP计算两个路径的相对路径
Jun 14 #PHP
深入解析PHP的引用计数机制
Jun 14 #PHP
深入解析PHP垃圾回收机制对内存泄露的处理
Jun 14 #PHP
Mysql的Root密码忘记,查看或修改的解决方法(图文介绍)
Jun 14 #PHP
You might like
ThinkPHP模板比较标签用法详解
2014/06/30 PHP
php中try catch捕获异常实例详解
2014/11/21 PHP
JavaScript 设计模式学习 Singleton
2009/07/27 Javascript
js控制滚动条缓慢滚动到顶部实现代码
2013/03/20 Javascript
js实现二代身份证号码验证详解
2014/11/20 Javascript
JS实现网站菜单拖拽移位效果的方法
2015/09/24 Javascript
jquery实现图片上传前本地预览功能
2016/05/10 Javascript
js防阻塞加载的实现方法
2016/09/09 Javascript
javascript之with的使用(阿里云、淘宝使用代码分析)
2016/10/11 Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
2017/02/18 Javascript
Node.js实现文件上传的示例
2017/06/28 Javascript
Mongoose中document与object的区别示例详解
2017/09/18 Javascript
详解angularjs实现echart图表效果最简洁教程
2017/11/29 Javascript
node.js基础知识小结
2018/02/26 Javascript
详解Vue项目编译后部署在非网站根目录的解决方案
2018/04/26 Javascript
JS实现DOM节点插入操作之子节点与兄弟节点插入操作示例
2018/07/30 Javascript
Vue实现导航栏的显示开关控制
2019/11/01 Javascript
详解小程序横屏方案对比
2020/06/28 Javascript
一起深入理解js中的事件对象
2021/02/06 Javascript
[50:04]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第二局
2016/02/28 DOTA
[57:59]完美世界DOTA2联赛循环赛 Ink Ice vs LBZS BO2第一场 11.05
2020/11/05 DOTA
浅谈python中scipy.misc.logsumexp函数的运用场景
2016/06/23 Python
python3中bytes和string之间的互相转换
2017/02/09 Python
使用python实现BLAST
2018/02/12 Python
python将类似json的数据存储到MySQL中的实例
2019/07/12 Python
python垃圾回收机制(GC)原理解析
2019/12/30 Python
css3进阶之less实现星空动画的示例代码
2019/09/10 HTML / CSS
css3实现二维码扫描特效的示例
2020/10/29 HTML / CSS
浅析数据存储的三种方式 cookie sessionstorage localstorage 的异同
2020/06/04 HTML / CSS
采用冷却技术的超自然舒适度:GhostBed床垫
2018/09/18 全球购物
Miller Harris官网:英国小众香水品牌
2020/09/24 全球购物
保险专业大专生求职信
2013/10/26 职场文书
讲文明树新风公益广告宣传方案
2014/02/25 职场文书
机关保密工作承诺书
2015/05/04 职场文书
七年级作文(600字3篇)
2019/09/24 职场文书
日本十大血腥动漫,那些被禁播的动漫盘点
2022/03/21 日漫