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 相关文章推荐
新版PHP将向Java靠拢
Oct 09 PHP
用ODBC的分页显示
Oct 09 PHP
PHP 5.3.0 安装分析心得
Aug 07 PHP
PHP 获取MySQL数据库里所有表的实现代码
Jul 13 PHP
修改apache配置文件去除thinkphp url中的index.php
Jan 17 PHP
PHP设计模式之观察者模式(Observer)详细介绍和代码实例
Apr 08 PHP
php导入大量数据到mysql性能优化技巧
Dec 29 PHP
discuz目录文件资料汇总
Dec 30 PHP
php header函数的常用http头设置
Jun 25 PHP
PHP格式化MYSQL返回float类型的方法
Mar 30 PHP
购物车实现的几种方式优缺点对比
May 02 PHP
不常用但很实用的PHP预定义变量分析
Jun 25 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
php5.2.0内存管理改进
2007/01/22 PHP
详解PHP中的mb_detect_encoding函数使用方法
2015/08/18 PHP
PHP生成条形码大揭秘
2015/09/24 PHP
php 截取中英文混合字符串的方法
2018/05/31 PHP
PHP商品秒杀问题解决方案实例详解【mysql与redis】
2019/07/22 PHP
php连接sftp的作用以及实例代码
2019/09/23 PHP
禁止刷新,回退的JS
2006/11/25 Javascript
dojo 之基础篇(二)之从服务器读取数据
2007/03/24 Javascript
javascript multibox 全选
2009/03/22 Javascript
Js基础学习资料
2010/11/23 Javascript
本地对象Array的原型扩展实现代码
2010/12/04 Javascript
jquery高级编程的最佳实践详解
2014/03/23 Javascript
javascript中undefined与null的区别
2015/08/16 Javascript
Js+Ajax,Get和Post在使用上的区别小结
2016/06/08 Javascript
基于JavaScript实现前端文件的断点续传
2016/10/17 Javascript
axios全局请求参数设置,请求及返回拦截器的方法
2018/03/05 Javascript
JS 中可以提升幸福度的小技巧(可以识别更多另类写法)
2018/07/28 Javascript
微信小程序学习笔记之文件上传、下载操作图文详解
2019/03/29 Javascript
微信小程序页面传多个参数跳转页面的实现方法
2019/05/17 Javascript
vue router 跳转时打开新页面的示例方法
2019/07/28 Javascript
vue 验证码界面实现点击后标灰并设置div按钮不可点击状态
2019/10/28 Javascript
js实现贪吃蛇小游戏
2019/10/29 Javascript
react实现移动端下拉菜单的示例代码
2020/01/16 Javascript
javascript实现扫雷简易版
2020/08/18 Javascript
Python实现的数据结构与算法之队列详解
2015/04/22 Python
使用Python编写提取日志中的中文的脚本的方法
2015/04/30 Python
在Django中管理Users和Permissions以及Groups的方法
2015/07/23 Python
关于python列表增加元素的三种操作方法
2018/08/22 Python
在django中查询获取数据,get, filter,all(),values()操作
2020/08/09 Python
HTML5新表单元素_动力节点Java学院整理
2017/07/12 HTML / CSS
建筑行业的大学生自我评价
2013/12/08 职场文书
创先争优活动党员公开承诺书
2014/08/29 职场文书
纪念九一八事变演讲稿:牢记历史,捍卫主权
2014/09/14 职场文书
公务员年度个人总结
2015/02/12 职场文书
2015年全民国防教育日活动总结
2015/03/23 职场文书
python实现双向链表原理
2022/05/25 Python