利用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下的权限算法的实现
Apr 28 PHP
PHP 翻页 实例代码
Aug 07 PHP
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
Mar 19 PHP
php上传文件中文文件名乱码的解决方法
Nov 01 PHP
php判断是否为json格式的方法
Mar 04 PHP
php数组删除元素示例
Mar 21 PHP
简单实用的PHP防注入类实例
Dec 05 PHP
详细解读PHP中接口的应用
Aug 12 PHP
PHP 输出缓冲控制(Output Control)详解
Aug 25 PHP
浅谈php中fopen不能创建中文文件名文件的问题
Feb 06 PHP
PHP+MySQL使用mysql_num_rows实现模糊查询图书信息功能
May 31 PHP
php使用curl获取header检测开启GZip压缩的方法
Aug 15 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 实现的将图片转换为TXT
2015/10/21 PHP
Yii2中添加全局函数的方法分析
2017/05/04 PHP
JavaScript 入门·JavaScript 具有全范围的运算符
2007/10/01 Javascript
Nodejs Post请求报socket hang up错误的解决办法
2014/09/25 NodeJs
get(0).tagName获得作用标签示例代码
2014/10/08 Javascript
js实现遮罩层弹出框的方法
2015/01/15 Javascript
javascript工厂模式和构造函数模式创建对象方法解析
2016/12/30 Javascript
angularjs中回车键触发某一事件的方法
2017/04/24 Javascript
angularjs项目的页面跳转如何实现(5种方法)
2017/05/25 Javascript
详解如何提高 webpack 构建 Vue 项目的速度
2017/07/03 Javascript
nodejs body-parser 解析post数据实例
2017/07/26 NodeJs
微信小程序 swiper组件构建轮播图的实例
2017/09/20 Javascript
利用jQuery实现简单的拖曳效果实例代码
2017/10/20 jQuery
vue-cli脚手架config目录下index.js配置文件的方法
2018/03/13 Javascript
详解JS中统计函数执行次数与执行时间
2018/09/04 Javascript
ES6使用export和import实现模块化的方法
2018/09/10 Javascript
如何利用node转发请求详解
2020/09/17 Javascript
[03:15]2014DOTA2国际邀请赛 专访国士无双信心满满
2014/07/12 DOTA
Python 常用 PEP8 编码规范详解
2017/01/22 Python
Python实现简单的获取图片爬虫功能示例
2017/07/12 Python
python不换行之end=与逗号的意思及用途
2017/11/21 Python
Python复制Word内容并使用格式设字体与大小实例代码
2018/01/22 Python
Python寻找两个有序数组的中位数实例详解
2018/12/05 Python
Python 互换字典的键值对实例
2019/02/12 Python
python2.7实现复制大量文件及文件夹资料
2019/08/31 Python
Django使用Celery加redis执行异步任务的实例内容
2020/02/20 Python
HTML5 SEO优化的一些建议
2020/08/27 HTML / CSS
巴西服装和鞋子购物网站:Marisa
2018/10/25 全球购物
奥地利体育网上商店:Gigasport
2019/10/09 全球购物
斯洛伐克最大的婴儿食品和用品网上商店:Feedo.sk
2020/12/21 全球购物
营销部内勤岗位职责
2014/04/30 职场文书
医院标语大全
2014/06/23 职场文书
2014年小学校长工作总结
2014/12/08 职场文书
法定代表人免职证明
2015/06/24 职场文书
2016年小学圣诞节活动总结
2016/03/31 职场文书
vue封装数字翻牌器
2022/04/20 Vue.js