利用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 相关文章推荐
BBS(php & mysql)完整版(二)
Oct 09 PHP
NT IIS下用ODBC连接数据库
Oct 09 PHP
php at(@)符号的用法简介
Jul 11 PHP
php 删除一个数组中的某个值.兼容多维数组!
Feb 18 PHP
PHP执行批量mysql语句的解决方法
May 02 PHP
php阻止页面后退的方法分享
Feb 17 PHP
php 生成自动创建文件夹并上传文件的示例代码
Mar 07 PHP
WordPress中自定义后台管理界面配色方案的小技巧
Dec 29 PHP
Codeigniter中集成smarty和adodb的方法
Mar 04 PHP
10个值得深思的PHP面试题
Nov 14 PHP
php 文件下载 出现下载文件内容乱码损坏的解决方法(推荐)
Nov 16 PHP
PHP使用文件锁解决高并发问题示例
Mar 29 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
用PHP写的基于Memcache的Queue实现代码
2011/11/27 PHP
WordPress开发中用于获取近期文章的PHP函数使用解析
2016/01/05 PHP
利用PHP访问MySql数据库的逻辑操作以及增删改查的实例讲解
2017/08/30 PHP
YII2框架中使用RBAC对模块,控制器,方法的权限控制及规则的使用示例
2020/03/18 PHP
JQuery 常用操作代码
2010/03/14 Javascript
Jquery如何实现点击时高亮显示代码
2014/01/22 Javascript
jQuery中:last选择器用法实例
2014/12/30 Javascript
基于jQuery实现的向下滑动二级菜单效果代码
2015/08/31 Javascript
Javascript中的数据类型之旅
2015/10/18 Javascript
微信小程序之数据双向绑定与数据操作
2017/05/12 Javascript
Vue监听一个数组id是否与另一个数组id相同的方法
2018/09/26 Javascript
深入理解nodejs搭建静态服务器(实现命令行)
2019/02/05 NodeJs
关于vue路由缓存清除在main.js中的设置
2019/11/06 Javascript
Vue.directive 实现元素scroll逻辑复用
2019/11/29 Javascript
在vue中axios设置timeout超时的操作
2020/09/04 Javascript
[45:59]完美世界DOTA2联赛PWL S2 FTD vs GXR 第二场 11.22
2020/11/24 DOTA
详细介绍Python函数中的默认参数
2015/03/30 Python
Python实现控制台进度条功能
2016/01/04 Python
python使用pyqt写带界面工具的示例代码
2017/10/23 Python
使用python实现抓取腾讯视频所有电影的爬虫
2019/04/15 Python
Python语言进阶知识点总结
2019/05/28 Python
解决django接口无法通过ip进行访问的问题
2020/03/27 Python
python打包生成so文件的实现
2020/10/30 Python
python Protobuf定义消息类型知识点讲解
2021/03/02 Python
女孩每月服装订阅盒:kidpik
2019/04/17 全球购物
法国女性内衣购物网站:Glamuse
2019/05/13 全球购物
求职简历中个人的自我评价
2013/12/01 职场文书
机电专业大学生职业规划书范文
2014/02/25 职场文书
优秀语文教师事迹
2014/05/18 职场文书
《中国梦我的梦》大学生演讲稿
2014/08/20 职场文书
个人四风问题原因分析及整改措施
2014/09/28 职场文书
刑事法律意见书
2015/06/04 职场文书
创业的9条正确思考方式
2019/08/26 职场文书
Redis遍历所有key的两个命令(KEYS 和 SCAN)
2021/04/12 Redis
AngularJS实现多级下拉框
2022/03/25 Javascript
python pygame 开发五子棋双人对弈
2022/05/02 Python