当前位置: 首页 > 编程日记 > 正文

PHP也玩并发,巧用curl 并发减少后端访问时间

说明:本人源自3篇博文

http://blog.csdn.net/zuiaituantuan/article/details/7048782

首先,先了解下 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方法,因此可简单排除这点~~~

http://log.dongsheng.org/2008/07/16/curl-multiple-handlers/

通常情况下 PHP 中的 cURL 是阻塞运行的,就是说创建一个 cURL 请求以后必须等它执行成功或者超时才会执行下一个请求,curl_multi_* 系列函数使并发访问成功可能,PHP 文档对这个函数的介绍不太详细,用法如下:

$requests = array('http://www.baidu.com', 'http://www.google.com');
$main    = curl_multi_init();
$results = array();
$errors  = array();
$info = array();
$count = count($requests);
for($i = 0; $i < $count; $i++) 
{  
$handles[$i] = curl_init($requests[$i]);  
var_dump($requests[$i]);  
curl_setopt($handles[$i], CURLOPT_URL, $requests[$i]);  
curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, 1);  
curl_multi_add_handle($main, $handles[$i]);
}
$running = 0; 
do {  
curl_multi_exec($main, $running);
} 
while($running > 0); 
for($i = 0; $i < $count; $i++)
{  $results[] = curl_multi_getcontent($handles[$i]);  
$errors[]  = curl_error($handles[$i]);  
$info[]    = curl_getinfo($handles[$i]);  
curl_multi_remove_handle($main, $handles[$i]);
}
curl_multi_close($main);
var_dump($results);
var_dump($errors);
var_dump($info);  


http://www.searchtb.com/2010/12/using-multicurl-to-improve-performance.html

前言:在我们平时的程序中难免出现同时访问几个接口的情况,平时我们用curl进行访问的时候,一般都是单个、顺序访问,假如有3个接口,每个接口耗时500毫秒那么我们三个接口就要花费1500毫秒了,这个问题太头疼了严重影响了页面访问速度,有没有可能并发访问来提高速度呢?今天就简单的说一下,利用curl并发来提高页面访问速度,希望大家多指导。1、老的curl访问方式以及耗时统计

<?php function curl_fetch($url, $timeout=3){     
$ch = curl_init();     
curl_setopt($ch, CURLOPT_URL, $url);     
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);     
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);     
$data = curl_exec($ch);     
$errno = curl_errno($ch);     
if ($errno>0) {         
$data = false;     
}     
curl_close($ch);     
return $data; 
} 
function microtime_float() 
{    
list($usec, $sec) = explode(" ", microtime());    
return ((float)$usec + (float)$sec); 
} 
$url_arr=array(      
"taobao"=>"http://www.taobao.com",      
"sohu"=>"http://www.sohu.com",      
"sina"=>"http://www.sina.com.cn",      
);  
$time_start = microtime_float();  
$data=array();  
foreach ($url_arr as $key=>$val)  
{      
$data[$key]=curl_fetch($val);  
}  
$time_end = microtime_float();  
$time = $time_end - $time_start;  
echo "耗时:{$time}"; 
?> 

耗时:0.614秒
2、curl并发访问方式以及耗时统计
<?php 
function curl_multi_fetch($urlarr=array()){     
$result=$res=$ch=array();     
$nch = 0;     
$mh = curl_multi_init();     
foreach ($urlarr as $nk => $url) {         
$timeout=2;         
$ch[$nch] = curl_init();         
curl_setopt_array($ch[$nch], array(         
CURLOPT_URL => $url,         
CURLOPT_HEADER => false,         
CURLOPT_RETURNTRANSFER => true,         
CURLOPT_TIMEOUT => $timeout,         
));         
curl_multi_add_handle($mh, $ch[$nch]);         
++$nch;     }     
/* wait for performing request */    
do {         
$mrc = curl_multi_exec($mh, $running);     
} while (CURLM_CALL_MULTI_PERFORM == $mrc);       
while ($running && $mrc == CURLM_OK) {         
// wait for network         
if (curl_multi_select($mh, 0.5) > -1) {             
// pull in new data;             
do {                 
$mrc = curl_multi_exec($mh, $running);             
} while (CURLM_CALL_MULTI_PERFORM == $mrc);         
}     
}       
if ($mrc != CURLM_OK) {         
error_log("CURL Data Error");     
}       
/* get data */    
$nch = 0;     
foreach ($urlarr as $moudle=>$node) {         
if (($err = curl_error($ch[$nch])) == '') {             
$res[$nch]=curl_multi_getcontent($ch[$nch]);             $result[$moudle]=$res[$nch];         }         
else        
{             
error_log("curl error");         
}         
curl_multi_remove_handle($mh,$ch[$nch]);         
curl_close($ch[$nch]);         
++$nch;     
}     
curl_multi_close($mh);     
return  $result; 
} 
$url_arr=array(      
"taobao"=>"http://www.taobao.com",      
"sohu"=>"http://www.sohu.com",      
"sina"=>"http://www.sina.com.cn",      
); 
function microtime_float() 
{    
list($usec, $sec) = explode(" ", microtime());    
return ((float)$usec + (float)$sec); 
} 
$time_start = microtime_float(); 
$data=curl_multi_fetch($url_arr); 
$time_end = microtime_float(); 
$time = $time_end - $time_start; 
echo "耗时:{$time}"; 
?> 

耗时:0.316秒
帅气吧整个页面访问后端接口的时间节省了一半
3、curl相关参数
来自:http://cn2.php.net/manual/en/ref.curl.php
curl_close — Close a cURL session
curl_copy_handle — Copy a cURL handle along with all of its preferences
curl_errno — Return the last error number
curl_error — Return a string containing the last error for the current session
curl_exec — Perform a cURL session
curl_getinfo — Get information regarding a specific transfer
curl_init — Initialize a cURL session
curl_multi_add_handle — Add a normal cURL handle to a cURL multi handle
curl_multi_close — Close a set of cURL handles
curl_multi_exec — Run the sub-connections of the current cURL handle
curl_multi_getcontent — Return the content of a cURL handle if CURLOPT_RETURNTRANSFER is set
curl_multi_info_read — Get information about the current transfers
curl_multi_init — Returns a new cURL multi handle
curl_multi_remove_handle — Remove a multi handle from a set of cURL handles
curl_multi_select — Wait for activity on any curl_multi connection
curl_setopt_array — Set multiple options for a cURL transfer
curl_setopt — Set an option for a cURL transfer
curl_version — Gets cURL version information

前端开发中的性能那点事(三)php的opcode缓存

前端开发中的性能那点事(一)巧用xdebug

相关文章:

ADSL自动更换IP地址源代码

有些网站限制IP地址&#xff0c;什么一个IP地址只能一次之类的。特别是投票网址&#xff0c;为了防止刷票&#xff0c;限制1个IP只允许投票一次&#xff01; 此程序采用Vs2010C#开发&#xff0c;提供全部源代码&#xff01;方便程序猿朋友二次开发&#xff01; 可以后台运行&am…

安全隐患:神经网络可以隐藏恶意软件

编译 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 凭借数百万和数十亿的数值参数&#xff0c;深度学习模型可以做到很多的事情&#xff0c;例如&#xff0c;检测照片中的对象、识别语音、生成文本以及隐藏恶意软件。加州大学圣地亚哥分校和伊利诺伊大学…

实现一个完美符合Promise/A+规范的Promise

原文在我的博客中&#xff1a;原文地址 如果文章对您有帮助&#xff0c;您的star是对我最好的鼓励&#xff5e; 简要介绍&#xff1a;Promise允许我们通过链式调用的方式来解决“回调地狱”的问题&#xff0c;特别是在异步过程中&#xff0c;通过Promise可以保证代码的整洁性和…

用递归法计算斐波那契数列的第n项

斐波纳契数列&#xff08;Fibonacci Sequence&#xff09;又称黄金分割数列&#xff0c;指的是这样一个数列&#xff1a;1、1、2、3、5、8、13、21、……在数学上&#xff0c;斐波纳契数列以如下被以递归的方法定义&#xff1a;F00&#xff0c;F11&#xff0c;FnF(n-1)F(n-2)&a…

ArrayList的内存泄露

2019独角兽企业重金招聘Python工程师标准>>> 大家先运行下下面这段代码&#xff0c;看看结果 public class MemoryLeak {public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {Overridepublic void run() {for (int i …

给 Python 初学者推荐的 IDE 哦!

作者 | 黄伟呢来源 | 数据分析与统计学之美总有一些Python初学者&#xff0c;会问到&#xff1a;学习Python&#xff0c;应该用什么Python IDE&#xff1f;了解到他们使用Python做什么之后&#xff0c;我总结了这篇文章。IDE是集成开发环境的缩写&#xff0c;通俗地说&#xff…

django 2.0路由配置变化

urlpatterns变量​​的语法 urlpatterns应该是path()和/或re_path()实例的Python列表。 首先&#xff0c;Django会使用根路由解析模块(root URLconf)来解析路由。 通常&#xff0c;这是ROOT_URLCONF设置的值&#xff0c;但是如果传入的HttpRequest对象具有urlconf属性&#xff…

用ext_skel,实现一个PHP扩展,添加到PHP并调用

http://www.shinrun.com/PHP 一、开始之前 1. 系统环境&#xff1a;FreeBSD 8.22. AP环境&#xff1a;即已经装好的Apache2.2.17、PHP5.3.8环境3. PHP源码&#xff1a;下载稳定版本源码到当前用户的目录&#xff0c;如&#xff0c;下载PHP 5.3.8到/usr/home/abc下。4. 其它要求…

关于第三方IOS的checkBox框架的使用

关于第三方IOS的checkBox框架的使用 这个框架是从github上下载获取的&#xff1a;M13Checkbox。 只是github的源码项目工程比较久远&#xff0c;所以我把代码部分拷贝到XCode 7.1.0新建的项目里。 下面是展示效果 客户端源码使用参考&#xff1a; 1 #import "ViewControll…

20 个 Pandas 数据实战案例,干货多多

作者 | 俊欣来源 | 关于数据分析与可视化今天我们讲一下pandas当中的数据过滤内容&#xff0c;小编之前也写过也一篇相类似的文章&#xff0c;但是是基于文本数据的过滤&#xff0c;大家有兴趣也可以去查阅一下。下面小编会给出大概20个案例来详细说明数据过滤的方法&#xff0…

Python创建和访问字典

>>> dict1 {a:1,b:2,c:3,d:4}>>> print(a的值是:,dict1[a])a的值是: 1>>> dict4 dict(我 快乐, 你 伤悲)SyntaxError: keyword cant be an expression>>> dict4[你] 改变悲伤>>> dict4{我: 快乐, 你: 改变悲伤}>>>…

C语言九阴真经

发现记忆力越来越差&#xff0c;所以干脆搞这么一个东西&#xff0c;就是把C语言的最常用的语法汇编在一起&#xff0c;不断完善。这样以后只要经常把这个回顾一下就可以了。不然去翻书太多了。。。f.h#define Area 1000 struct student{char *last_name;int student_id;char …

听障人士的“有声桥梁”:百度智能云曦灵-AI手语平台发布

在刚刚落幕的冰雪赛事中&#xff0c;百度智能云曦灵为央视新闻打造的AI手语主播正式上岗&#xff0c;她以流畅、专业的手语服务实时传递冰雪运动的激情。然而在日常生活中&#xff0c;听障人士想要方便地获取信息仍面临着众多困难&#xff0c;无障碍窗口稀缺的问题亟待解决。 …

模拟实现: strstr strcpy strlen strcat strcmp memcpy memmove

模拟实现&#xff1a;strstrstrcpystrlenstrcatstrcmpmemcpymemmove1 strstr 字符串中查找子字符串char * my_strstr(const char *dest, const char *src) {const char *ret dest;const char *p dest;const char *q src;assert(dest ! NULL && src ! NULL); while(r…

【Spring Security】五、自定义过滤器

在之前的几篇security教程中&#xff0c;资源和所对应的权限都是在xml中进行配置的&#xff0c;也就在http标签中配置intercept-url&#xff0c;试想要是配置的对象不多&#xff0c;那还好&#xff0c;但是平常实际开发中都往往是非常多的资源和权限对应&#xff0c;而且写在配…

一星期没完成Ansible任务

这个星期&#xff0c;前4天&#xff0c;我在看Nginx&#xff0c;没有深入Ansible。 这几天我有思考做Ansible的哪个方面&#xff0c;现在我用Ansible可以用&#xff0c;但是没有生产环境&#xff0c;我对基础部分热情不是特别大&#xff0c;应该是基础部分大家在弄&#xff0c;…

Python 批量处理 Excel 数据后,导入 SQL Server

作者 | 老表来源 | 简说Python1、前言2、开始动手动脑2.1 拆解明确需求2.2 安装第三方包2.3 读取excel数据2.4 特殊数据数据处理2.5 其他需求2.6 完整调用代码1、前言今天教大家一个需求&#xff1a;有很多Excel&#xff0c;需要批量处理&#xff0c;然后存入不同的数据表中。2…

最经典的计算机网络新书推荐--计算机网络(第5版)Tanenbaum著中文版上市

作者&#xff1a;Tanenbaum是全球最著名的计算机科学家。linux之父Linus当年就是参考Tanenbaum写的MINIX&#xff01; Tanenbaum《计算机网络(第5版) 》《现代操作系统(第3版) 》《操作系统设计与实现(第3版) 》《分布式系统原理与范型(第2版) 》《计算机组成结构化方法&#x…

elasticsearch简单操作(二)

让我们建立一个员工目录&#xff0c;假设我们刚好在Megacorp工作&#xff0c;这时人力资源部门出于某种目的需要让我们创建一个员工目录&#xff0c;这个目录用于促进人文关怀和用于实时协同工作&#xff0c;所以它有以下不同的需求&#xff1a;1、数据能够包含多个值的标签、数…

苹果放大招?「廉价版」5G iPhone 将揭晓,M2芯片来袭?

整理 | 张洁来源 | CSDN3 月 2 日&#xff0c;苹果公司正式宣布将于北京时间 3 月 9 日凌晨 2 点举办 2022 年的首场活动&#xff0c;主题为“peek performance&#xff08;高能传送&#xff09;”。与去年一样&#xff0c;苹果 2022 年的第一场活动将继续以线上的方式进行。活…

PHP 预编译加速: eAccelerator的安装和性能比较

eAccelerator已经是很常用的PHP平台预编译加速的手段了。今天在自己机器上尝试安装了一下&#xff0c;备忘如下&#xff1a; 获得源代码&#xff1a;http://bart.eaccelerator.net/source/编译&#xff1a;需要有autoconf支持&#xff0c;解包后在源程序目录下&#xff1a;/usr…

合并区间(LintCode)

合并区间 给出若干闭合区间&#xff0c;合并所有重叠的部分。 样例 给出的区间列表 > 合并后的区间列表&#xff1a; [ [[1, 3], [1, 6],[2, 6], > [8, 10],[8, 10], [15, 18][15, 18] ] ]挑战 O(…

Kylin集群部署和cube使用

Kylin集群部署和cube使用 安装集群环境节点 Kylin节点模式 Ip 内存 磁盘Node1 All 192.167.71.11 2G 80GNode2 query 192.168.71.12 1.5G 80GNode3 query 192.168.71.13 1.5G 80GKylin工作原理如下&#xff1a; 集群时间同步Ntp服务自行设置安装kylin之前所需要的环境Hadoop-2.…

就是个控制结构,Scala 能有什么新花样呢?

作者 | luanhz来源 | 小数志导读编程语言中最为基础的一个概念是控制结构&#xff0c;几乎任何代码都无时无刻不涉及到&#xff0c;其实也就无外乎3种&#xff1a;顺序、分支和循环。本文就来介绍Scala中控制结构&#xff0c;主要是分支和循环。Scala中的控制结构实质上与其他编…

快速开发一个PHP扩展

快速开发一个PHP扩展 作者&#xff1a;heiyeluren时间&#xff1a;2008-12-5博客&#xff1a;http://blog.csdn.net/heiyeshuwu 本文通过非常快速的方式讲解了如何制作一个PHP 5.2 环境的扩展&#xff08;PHP Extension&#xff09;&#xff0c;希望能够在图文的方式下让想快速…

oracle11g的安装

目录层次&#xff1a;linux->oracle软件->dbca数据库安装过程&#xff1a;虚拟机->linux->VMtools->拷贝数据库软件->创建一个目录mkdir->创建组.用户->修改根目录->设置参数->解压 >安装->oracle完成参考&#xff1a;安装oracle软件linu…

python 100例(10)

2019独角兽企业重金招聘Python工程师标准>>> 题目&#xff1a;古典问题&#xff1a;有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子总数为多…

cocos2dx-3.9 集成admob

Part 1: 安装GoogleMobileAds framework &#xff08;即admob&#xff09; 1. 安装Cocoapods&#xff0c;否则解决依赖关系和配置真的会把人不累死也得烦死 sudo gem install cocoapods 国内用户安装过程中可能遇到SSL连接出错的问题&#xff0c;请参考 Cocoapod安装过程中的幺…

用C语言扩展PHP功能

用C语言扩展PHP功能建议读者群&#xff1a;熟悉c,linux,php PHP经过最近几年的发展已经非常的流行&#xff0c;而且PHP也提供了各种各样非常丰富的函数。但有时候我们还是需要来扩展PHP。比如&#xff1a;我们自己开发了一个数据库系统&#xff0c;而且有自己的库函数来操作数…

手把手快速实现 Resnet 残差模型实战

作者 | 李秋键 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 引言&#xff1a;随着深度学习的发展&#xff0c;网络模型的深度也随之越来越深&#xff0c;但随着网络模型深度的加深&#xff0c;往往会曾在这随着模型深度的加大&#xff0c;模型准确率反而下降的问…