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输出控制功能在简繁体转换中的应用
Oct 09 PHP
10条PHP编程习惯助你找工作
Sep 29 PHP
php中删除字符串中最先出现某个字符的实现代码
Feb 03 PHP
如何使用php绘制在图片上的正余弦曲线
Jun 08 PHP
Zend Framework教程之模型Model基本规则和使用方法
Mar 04 PHP
PHP 闭包详解及实例代码
Sep 28 PHP
关于php几种字符串连接的效率比较(详解)
Feb 22 PHP
php base64 编码与解码实例代码
Mar 21 PHP
centos下file_put_contents()无法写入文件的原因及解决方法
Apr 01 PHP
PHP小白必须要知道的php基础知识(超实用)
Oct 10 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
Feb 10 PHP
PHP时间戳和日期相互转换操作实例小结
Dec 18 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
浅析memcache启动以及telnet命令详解
2013/06/28 PHP
PHP中构造函数和析构函数解析
2014/10/10 PHP
php创建无限级树型菜单
2015/11/05 PHP
Yii2简单实现给表单添加验证码的方法
2016/07/18 PHP
laravel邮件发送的实现代码示例
2020/01/31 PHP
JS URL传中文参数引发的乱码问题
2009/09/02 Javascript
js中传递特殊字符(+,&amp;)的方法
2014/01/16 Javascript
jquery的ajax和getJson跨域获取json数据的实现方法
2014/02/04 Javascript
JavaScript打印网页指定区域的例子
2014/05/03 Javascript
原生javascript实现Tab选项卡切换功能
2015/01/12 Javascript
JavaScript父子窗体间的调用方法
2015/03/31 Javascript
js实现内容显示并使用json传输数据
2016/03/16 Javascript
把json格式的字符串转换成javascript对象或数组的方法总结
2016/11/03 Javascript
关于Vue.js 2.0的Vuex 2.0 你需要更新的知识库
2016/11/30 Javascript
Vue.js仿Metronic高级表格(一)静态设计
2017/04/17 Javascript
详解webpack进阶之loader篇
2017/08/23 Javascript
jquery使用iscorll实现上拉、下拉加载刷新
2017/10/26 jQuery
vue-cli 使用vue-bus来全局控制的实例讲解
2018/09/15 Javascript
小程序二次贝塞尔曲线实现购物车商品曲线飞入效果
2019/01/07 Javascript
jQuery加PHP实现图片上传并提交的示例代码
2020/07/16 jQuery
[09:34]2018DOTA2国际邀请赛寻真——永不放弃的iG
2018/08/14 DOTA
用python实现批量重命名文件的代码
2012/05/25 Python
Python中logging模块的用法实例
2014/09/29 Python
进一步探究Python的装饰器的运用
2015/05/05 Python
opencv python 图像去噪的实现方法
2018/08/31 Python
Python爬虫常用小技巧之设置代理IP
2018/09/13 Python
Python+OpenCv制作证件图片生成器的操作方法
2019/08/21 Python
Python调用C/C++的方法解析
2020/08/05 Python
python实现企业微信定时发送文本消息的实例代码
2020/11/25 Python
canvas进阶之贝塞尔公式推导与物体跟随复杂曲线的轨迹运动
2018/01/10 HTML / CSS
泰国在线书店:SE-ED
2020/06/21 全球购物
葬礼司仪主持词
2014/03/31 职场文书
团委书记的竞聘演讲稿
2014/04/24 职场文书
物业保安辞职信
2015/05/12 职场文书
校园安全教育心得体会
2016/01/15 职场文书
win11怎么用快捷键锁屏? windows11锁屏的几种方法
2021/11/21 数码科技