php使用curl_init()和curl_multi_init()多线程的速度比较详解


Posted in PHP onAugust 15, 2018

本文实例讲述了php使用curl_init()和curl_multi_init()多线程的速度比较。分享给大家供大家参考,具体如下:

php中curl_init()的作用很大,尤其是在抓取网页内容或文件信息的时候,例如之前文章《php使用curl获取header检测开启GZip压缩》就介绍到curl_init()的强大。

curl_init()处理事物是单线程模式,如果需要对事务处理走多线程模式,那么php里提供了一个函数curl_multi_init()给我们,这就是多线程模式处理事务的函数。

curl_init()curl_multi_init()的速度比较

curl_multi_init()多线程能提高网页的处理速度吗?今天我通过实验来验证一下这个问题。

今天我的测试很简单,那就是要抓取www.webkaka.com网页的内容,要连续抓5次,分别用curl_init()curl_multi_init()函数来完成,记录两者的耗时,比较得出结论。

首先,用curl_init()单线程连续抓5次www.webkaka.com网页的内容。

程序代码如下:

<?php
$mtime = explode(" ", microtime());
$mtime = $mtime[1].($mtime[0] * 1000);
$mtime2 = explode(".", $mtime);
$mtime = $mtime2[0];
echo $mtime;
echo "<br>";
for($i=1; $i<=5; $i++){
$szUrl = 'http://www.webkaka.com/';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $szUrl);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_ENCODING, '');
$data=curl_exec($curl);
echo $data;
echo "<br>";
$mtime_ = explode(" ", microtime());
$mtime_ = $mtime_[1].($mtime_[0] * 1000);
$mtime2_ = explode(".", $mtime_);
$mtime_ = $mtime2_[0];
echo $mtime_;
echo "<br>";
echo $mtime_ - $mtime;
}
?>

然后,用curl_multi_init()多线程连续抓5次www.webkaka.com网页的内容。

代码如下:

<?php
echo date("Y-m-d H:m:s",time());
echo " ";
echo floor(microtime()*1000);
echo "<br>";
$mtime = explode(" ", microtime());
$mtime = $mtime[1].($mtime[0] * 1000);
$mtime2 = explode(".", $mtime);
$mtime = $mtime2[0];
echo $mtime;
echo "<br>";
$urls = array(
'http://www.webkaka.com',
'http://www.webkaka.com',
'http://www.webkaka.com',
'http://www.webkaka.com',
'http://www.webkaka.com');
print_r(async_get_url($urls)); // [0] => example1, [1] => example2
echo "<br>";
echo date("Y-m-d H:m:s",time());
echo " ";
echo floor(microtime()*1000);
echo "<br>";
$mtime_ = explode(" ", microtime());
$mtime_ = $mtime_[1].($mtime_[0] * 1000);
$mtime2_ = explode(".", $mtime_);
$mtime_ = $mtime2_[0];
echo $mtime_;
echo "<br>";
echo $mtime_ - $mtime;
function async_get_url($url_array, $wait_usec = 0)
{
  if (!is_array($url_array))
    return false;
  $wait_usec = intval($wait_usec);
  $data  = array();
  $handle = array();
  $running = 0;
  $mh = curl_multi_init(); // multi curl handler
  $i = 0;
  foreach($url_array as $url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return don't print
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 302 redirect
    curl_setopt($ch, CURLOPT_MAXREDIRS, 7);
    curl_multi_add_handle($mh, $ch); // 把 curl resource 放进 multi curl handler 里
    $handle[$i++] = $ch;
  }
  /* 执行 */
  do {
    curl_multi_exec($mh, $running);
    if ($wait_usec > 0) /* 每个 connect 要间隔多久 */
      usleep($wait_usec); // 250000 = 0.25 sec
  } while ($running > 0);
  /* 读取资料 */
  foreach($handle as $i => $ch) {
    $content = curl_multi_getcontent($ch);
    $data[$i] = (curl_errno($ch) == 0) ? $content : false;
  }
  /* 移除 handle*/
  foreach($handle as $ch) {
    curl_multi_remove_handle($mh, $ch);
  }
  curl_multi_close($mh);
  return $data;
}
?>

为了避免随机性,我分别测了5次(用CTRL+F5强行刷新的方式),数据如下:

curl_init():

第一次 第二次 第三次 第四次 第五次 平均
耗时(ms) 3724 3615 2540 1957 2794 2926

curl_multi_init():

第一次 第二次 第三次 第四次 第五次 平均
耗时(ms) 4275 2912 3691 4198 3891 3793

从测试结果来看,我们发现两种方法的耗时差不了太多,只有700多毫秒。很多人原本以为多线程比单线程耗时会短很多,实际上并不是这样的,从数据来看,多线程反而比单线程耗时更多了一点。不过,对于某些事务来说,用多线程来处理不一定是为了追求速度,这个是需要注意的。

关于curl_multi_init()

一般来说,想到要用curl_multi_init()时,目的是要同时请求多个url,而不是一个一个依次请求,否则就要curl_init()了。

不过,在使用curl_multi的时候,你可能遇到cpu消耗过高、网页假死等现象,可以看看《PHP使用curl_multi_select解决curl_multi网页假死问题》

使用curl_multi的步骤总结如下:

  • 第一步:调用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

各函数作用解释:

curl_multi_init()
初始化一个curl批处理句柄资源。

curl_multi_add_handle()
向curl批处理会话中添加单独的curl句柄资源。curl_multi_add_handle()函数有两个参数,第一个参数表示一个curl批处理句柄资源,第二个参数表示一个单独的curl句柄资源。

curl_multi_exec()
解析一个curl批处理句柄,curl_multi_exec()函数有两个参数,第一个参数表示一个批处理句柄资源,第二个参数是一个引用值的参数,表示剩余需要处理的单个的curl句柄资源数量。

curl_multi_remove_handle()
移除curl批处理句柄资源中的某个句柄资源,curl_multi_remove_handle()函数有两个参数,第一个参数表示一个curl批处理句柄资源,第二个参数表示一个单独的curl句柄资源。

curl_multi_close()
关闭一个批处理句柄资源。

curl_multi_getcontent()
在设置了CURLOPT_RETURNTRANSFER的情况下,返回获取的输出的文本流。

curl_multi_info_read()
获取当前解析的curl的相关传输信息。

实例

请看本文里async_get_url()的写法。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
上传文件先创建目录 再上传到目录里面去
Dec 29 PHP
七款最流行的PHP本地服务器分享
Feb 19 PHP
PHP包含文件函数include、include_once、require、require_once区别总结
Apr 05 PHP
PHP中基本HTTP认证技巧分析
Mar 16 PHP
Mac环境下php操作mysql数据库的方法分享
May 11 PHP
PHP实现过滤各种HTML标签
May 17 PHP
php实现随机生成易于记忆的密码
Jun 19 PHP
php利用云片网实现短信验证码功能的示例代码
Nov 18 PHP
PHPUnit测试私有属性和方法功能示例
Jun 12 PHP
PHP实现负载均衡的加权轮询方法分析
Aug 22 PHP
php判断电子邮件是否正确方法
Dec 04 PHP
PHP实现基本留言板功能原理与步骤详解
Mar 26 PHP
php使用curl获取header检测开启GZip压缩的方法
Aug 15 #PHP
深入研究PHP中的preg_replace和代码执行
Aug 15 #PHP
PHP中一个有趣的preg_replace函数详解
Aug 15 #PHP
PHP使用curl_multi_select解决curl_multi网页假死问题的方法
Aug 15 #PHP
php+croppic.js实现剪切上传图片功能
Aug 14 #PHP
PHP设计模式之委托模式定义与用法简单示例
Aug 13 #PHP
PHP设计模式之建造者模式定义与用法简单示例
Aug 13 #PHP
You might like
让这部DC动画新作刷新你的认知
2020/03/03 欧美动漫
上海牌131型七灯四波段四喇叭一级收音机
2021/03/02 无线电
php正则过滤html标签、空格、换行符的代码(附说明)
2010/10/25 PHP
PHP基于SPL实现的迭代器模式示例
2018/04/22 PHP
js 变量类型转换常用函数与代码[比较全]
2009/12/01 Javascript
JavaScript调用Activex控件的事件的实现方法
2010/04/11 Javascript
js汉字排序问题 支持中英文混排,兼容各浏览器,包括CHROME
2011/12/20 Javascript
基于jquery实现后台左侧菜单点击上下滑动显示
2013/04/11 Javascript
一个很有趣3D球状标签云兼容IE8
2014/08/22 Javascript
分享使用AngularJS创建应用的5个框架
2015/12/05 Javascript
jQuery延迟执行的实现方法
2016/12/21 Javascript
JS实现的tab切换选项卡效果示例
2017/02/28 Javascript
jQuery设计思想
2017/03/07 Javascript
详解webpack的配置文件entry与output
2017/08/21 Javascript
vue中实现滚动加载更多的示例
2017/11/08 Javascript
Webpack path与publicPath的区别详解
2018/05/03 Javascript
JS插件clipboard.js实现一键复制粘贴功能
2020/12/04 Javascript
javacript replace 正则取字符串中的值并替换【推荐】
2018/09/13 Javascript
Vue递归实现树形菜单方法实例
2018/11/06 Javascript
vue组件间通信六种方式(总结篇)
2019/05/15 Javascript
SSM+layUI 根据登录信息显示不同的页面方法
2019/09/20 Javascript
Javascript实现简易天数计算器
2020/05/18 Javascript
用PyInstaller把Python代码打包成单个独立的exe可执行文件
2018/05/26 Python
python nohup 实现远程运行不宕机操作
2020/04/16 Python
利用python中的matplotlib打印混淆矩阵实例
2020/06/16 Python
Pytorch 卷积中的 Input Shape用法
2020/06/29 Python
CSS3实现类似翻书效果的过渡动画的示例代码
2019/09/06 HTML / CSS
深入剖析HTML5 内联框架iFrame
2016/05/04 HTML / CSS
物流经理自我评价
2013/09/23 职场文书
毕业生幼师求职自荐信
2013/10/01 职场文书
平面设计的岗位职责
2013/11/08 职场文书
大学生村官考核材料
2014/05/23 职场文书
小学生迎国庆演讲稿
2014/09/05 职场文书
小学班级标语口号大全
2015/12/26 职场文书
2016读书月活动心得体会
2016/01/14 职场文书
JS精髓原型链继承及构造函数继承问题纠正
2022/06/16 Javascript