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 相关文章推荐
第十节 抽象方法和抽象类 [10]
Oct 09 PHP
用php和MySql来与ODBC数据连接
Oct 09 PHP
Cannot modify header information错误解决方法
Oct 08 PHP
php mysql Errcode: 28 终极解决方法
Jul 01 PHP
PHP5权威编程阅读学习笔记 附电子书下载
Jul 05 PHP
PHP 5.3新增魔术方法__invoke概述
Jul 23 PHP
PHP使用xmllint命令处理xml与html的方法
Dec 15 PHP
php验证码的制作思路和实现方法
Nov 12 PHP
PHP使用Memcache时模拟命名空间及缓存失效问题的解决
Feb 27 PHP
PHP中strpos、strstr和stripos、stristr函数分析
Jun 11 PHP
php中请求url的五种方法总结
Jul 13 PHP
浅析PHP7的多进程及实例源码
Apr 14 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
什么是短波收听SWL
2021/03/01 无线电
php FPDF类库应用实现代码
2009/03/20 PHP
PHP导出Excel实例讲解
2016/01/24 PHP
thinkPHP实现MemCache分布式缓存功能
2016/03/23 PHP
Laravel 5.2 文档 数据库 ―― 起步介绍
2019/10/21 PHP
javascript一点特殊用法
2008/05/28 Javascript
ExtJS实现文件下载的方法实例
2013/11/09 Javascript
用js判断输入是否为中文的函数
2014/03/10 Javascript
jQuery知识点整理
2015/01/30 Javascript
JavaScript使用Replace进行字符串替换的方法
2015/04/14 Javascript
深入讲解AngularJS中的自定义指令的使用
2015/06/18 Javascript
jquery中checkbox使用方法简单实例演示
2015/11/24 Javascript
vuejs使用递归组件实现树形目录的方法
2017/09/30 Javascript
Node.js中,在cmd界面,进入退出Node.js运行环境的方法
2018/05/12 Javascript
解决layui的input独占一行的问题
2019/09/10 Javascript
JavaScript使用百度ECharts插件绘制饼图操作示例
2019/11/26 Javascript
[01:32:10]NAVI vs VG Supermajor 败者组 BO3 第一场 6.5
2018/06/06 DOTA
Python使用cx_Oracle调用Oracle存储过程的方法示例
2017/10/07 Python
Python 实现遥感影像波段组合的示例代码
2019/08/04 Python
基于Python中random.sample()的替代方案
2020/05/23 Python
opencv 形态学变换(开运算,闭运算,梯度运算)
2020/07/07 Python
利用PyQt5+Matplotlib 绘制静态/动态图的实现代码
2020/07/13 Python
通过实例了解Python异常处理机制底层实现
2020/07/23 Python
Python configparser模块应用过程解析
2020/08/14 Python
python安装第三方库如xlrd的方法
2020/10/31 Python
马来西亚网上购物平台:ezbuy
2018/02/13 全球购物
了解AppleShare protocol(AppleShare协议)吗
2015/08/28 面试题
物业管理专业个人的自我评价
2013/11/19 职场文书
小学美术教学反思
2014/02/01 职场文书
十佳美德少年事迹材料
2014/02/05 职场文书
法学函授自我鉴定
2014/02/06 职场文书
经销商年会策划方案
2014/05/29 职场文书
应届本科毕业生求职信
2014/07/23 职场文书
明星员工获奖感言
2014/08/14 职场文书
2015年禁毒宣传活动总结
2015/03/25 职场文书
2015年音乐教师个人工作总结
2015/05/20 职场文书