利用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中str_replace函数使用小结
Oct 11 PHP
PHP之COOKIE支持详解
Sep 20 PHP
php使用curl访问https示例分享
Jan 17 PHP
PHP延迟静态绑定示例分享
Jun 22 PHP
采用memcache在web集群中实现session的同步会话
Jul 05 PHP
PHP实现取得HTTP请求的原文
Aug 18 PHP
PHP与MYSQL中UTF8 中文排序示例代码
Oct 23 PHP
php调用shell的方法
Nov 05 PHP
WIFI万能钥匙密码查询接口实例
Sep 28 PHP
php简单解析mysqli查询结果的方法(2种方法)
Jun 29 PHP
PHP实现添加购物车功能
Mar 06 PHP
ThinkPHP5.1+Ajax实现的无刷新分页功能示例
Feb 10 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 中的一些经验积累
2006/10/09 PHP
php 中英文语言转换类代码
2011/08/11 PHP
浅析虚拟主机服务器php fsockopen函数被禁用的解决办法
2013/08/07 PHP
PHP中cookie和session的区别实例分析
2014/08/28 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
Thinkphp 框架基础之入口文件功能、定义与用法分析
2020/04/27 PHP
用Jquery实现可编辑表格并用AJAX提交到服务器修改数据
2009/12/27 Javascript
jQuery Selector选择器小结
2010/05/06 Javascript
取得窗口大小 兼容所有浏览器的js代码
2011/08/09 Javascript
Node连接mysql数据库方法介绍
2017/02/07 Javascript
JavaScript实现图片本地预览功能【不用上传至服务器】
2017/09/20 Javascript
详解Angular5路由传值方式及其相关问题
2018/04/28 Javascript
vue.js计算属性computed用法实例分析
2018/07/06 Javascript
如何实现iframe父子传参通信
2020/02/05 Javascript
vue使用微信扫一扫功能的实现代码
2020/04/11 Javascript
记一次vue跨域的解决
2020/10/21 Javascript
用Python实现一个简单的多线程TCP服务器的教程
2015/05/05 Python
python生成tensorflow输入输出的图像格式的方法
2018/02/12 Python
python使用openpyxl库修改excel表格数据方法
2018/05/03 Python
利用Python读取txt文档的方法讲解
2018/06/23 Python
pytorch之ImageFolder使用详解
2020/01/06 Python
python logging模块的使用
2020/09/07 Python
Python基于callable函数检测对象是否可被调用
2020/10/16 Python
解决python3.6用cx_Oracle库连接Oracle的问题
2020/12/07 Python
python3 googletrans超时报错问题及翻译工具优化方案 附源码
2020/12/23 Python
加热夹克:RAVEAN
2018/10/19 全球购物
法律专业自我鉴定
2013/10/03 职场文书
大学生职业生涯规划书模版
2013/12/30 职场文书
模具专业毕业推荐信
2014/03/08 职场文书
三八红旗集体先进事迹材料
2014/05/22 职场文书
校园安全标语
2014/06/07 职场文书
市场营销策划方案
2014/06/11 职场文书
教育专业毕业生推荐信
2014/07/10 职场文书
四风问题查摆材料
2014/08/25 职场文书
大学生暑期社会实践证明范本
2014/10/24 职场文书
CSS 新特性 contain控制页面的重绘与重排问题
2021/04/30 HTML / CSS