http://www.trackself.com/code/curl_multi.html
function cmi($connomains,$killspace=TRUE,$forhtml=TRUE,$timeout=6,$header=0,$follow=1){
/*
cmi该函数的目的在于并发请求多个url,然后返回http://www.trackself.com
编写,真正的PHP并发
原文发表在http://www.trackself.com/archives/463.html
此并发请求在url多于2的时候,明显比for ... file_get_contents ...要优很多
核心是curl库的curl_multi方法
用法:
$urls=array(
'http://www.google.com',
'http://www.baidu.com',
'http://sina.com',
'http://163.com'
)
$htmls=cmi($urls);
print_r($htmls);
//传入的$connomains是URL一维数组,由http://www.trackself.com编写
//该函数的目的在于并发请求多个url,然后返回源码
//以一次性略增加CPU为代价
//来减轻服务器因为for ... file_get_contents ...的长时连接负担及内存和CPU的负担,所以并发数不要大多(50以内效果非常好),尽量不要用于单页面或3页面以内的请求
//$killspace为真时表示自动去掉HTML中换行及多余的空白,$forhtml为真时表示反回源码,为faluse时就是并发执行请求了(可以用于计划任务)
//后面的几个参数的详细说明请看注释,毕竟函数不长
*/
$res=array();
$urlsa=array();
$results=array();
$mh = curl_multi_init();//创建多curl对象,为了几乎同时执行
foreach ($connomains as $i => $url) {
$conn[$i]=curl_init($url);//若url中含有gb2312汉字,例如FTP时,要在传入url的时候处理一下,这里不用
curl_setopt($conn[$i], CURLOPT_TIMEOUT, $timeout);//此时间须根据页面的HTML源码出来的时间,一般是在1s内的,慢的话应该也不会6秒,极慢则是在16秒内
curl_setopt($conn[$i], CURLOPT_HEADER, $header);//不返回请求头,只要源码
curl_setopt($conn[$i],CURLOPT_RETURNTRANSFER,1);//必须为1
curl_setopt($conn[$i], CURLOPT_FOLLOWLOCATION, $follow);//如果页面含有自动跳转的代码如301或者302HTTP时,自动拿转向的页面
curl_multi_add_handle ($mh,$conn[$i]);//关键,一定要放在上面几句之下,将单curl对象赋给多对象
}
//下面一大步的目的是为了减少cpu的无谓负担,暂时不明,来自php.net的建议,几乎是固定用法
do {
$mrc = curl_multi_exec($mh,$active);//当无数据时或请求暂停时,active=true
} while ($mrc == CURLM_CALL_MULTI_PERFORM);//当正在接受数据时
while ($active and $mrc == CURLM_OK) {//当无数据时或请求暂停时,active=true,为了减少cpu的无谓负担,这一步很难明啊
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
/
//下面返回结果
foreach ($connomains as $i => $url) {
$cinfo=curl_getinfo($conn[$i]);//可用于取得一些有用的参数,可以认为是header
$url=$cinfo[url];//真实url,有些url
if($killspace){//有点水消耗
$str=trim(curl_multi_getcontent($conn[$i]));
$str = preg_replace('//s(?=/s)/', '', $str);//去掉跟随别的挤在一块的空白
$str = preg_replace('/[/n/r/t]/', ' ', $str); //最后,去掉非space 的空白,用一个空格代替
$res[$i]=stripslashes($str);//取得对象源码,并取消换行,节约内存的同时,可以方便作正则处理
}else{
$res[$i]=curl_multi_getcontent($conn[$i]);
}
if(!$forhtml){//节约内存
$res[$i]=NULL;
}
/*下面这一段放一些高消耗的程序代码,用来处理HTML,我保留的一句=NULL是要提醒,及时清空对象释放内存,此程序在并发过程中如果源码太大,内在消耗严重
//事实上,这里应该做一个callback函数或者你应该将你的逻辑直接放到这里来,我为了程序可重复,没这么做
preg_match_all($preg,$res[$i],$matchlinks);
$res[$i]=NULL;
*/
curl_close($conn[$i]);//关闭所有对象
curl_multi_remove_handle($mh , $conn[$i]); //用完马上释放资源
}
curl_multi_close($mh);$mh=NULL;$conn=NULL;
return $res;
}//cmi
下面是版本二,几乎一至的代码,但输出的形式改为为带key;
function cmi($connomains,$killspace=TRUE,$forhtml=TRUE,$timeout=6,$header=0,$follow=1){
/*
cmi该函数的目的在于并发请求多个url,然后返回http://www.trackself.com
编写,真正的PHP并发
原文发表在http://www.trackself.com/archives/463.html
此并发请求在url多于2的时候,明显比for ... file_get_contents ...要优很多
核心是curl库的curl_multi方法
用法:
//array_flip(array_flip($connomains))
$urls=array(
'http://www.google.com',
'http://www.baidu.com',
'http://sina.com',
'http://163.com'
)
$urls=array_flip(array_flip($connomains));//去除url中的重复的项,注意传入urls时一定要系合法的url表达,虽然不会影响其它url执行,但会减慢执行速度
$htmls=cmi($urls);
print_r($htmls);
//传入的$connomains是URL一维数组,由http://www.trackself.com编写
//该函数的目的在于并发请求多个url,然后返回源码
//以一次性略增加CPU为代价
//来减轻服务器因为for ... file_get_contents ...的长时连接负担及内存和CPU的负担,所以并发数不要大多(50以内效果非常好),尽量不要用于单页面或3页面以内的请求
//$killspace为真时表示自动去掉HTML中换行及多余的空白,$forhtml为真时表示反回源码,为faluse时就是并发执行请求了(可以用于计划任务)
//后面的几个参数的详细说明请看注释,毕竟函数不长
*/
$res=array();//用于保存结果
//$connomains=array_flip(array_flip($connomains));//去除url中的重复项
$mh = curl_multi_init();//创建多curl对象,为了几乎同时执行
foreach ($connomains as $i => $url) {
$conn[$url]=curl_init($url);//若url中含有gb2312汉字,例如FTP时,要在传入url的时候处理一下,这里不用
curl_setopt($conn[$url], CURLOPT_TIMEOUT, $timeout);//此时间须根据页面的HTML源码出来的时间,一般是在1s内的,慢的话应该也不会6秒,极慢则是在16秒内
curl_setopt($conn[$url], CURLOPT_HEADER, $header);//不返回请求头,只要源码
curl_setopt($conn[$url],CURLOPT_RETURNTRANSFER,1);//必须为1
curl_setopt($conn[$url], CURLOPT_FOLLOWLOCATION, $follow);//如果页面含有自动跳转的代码如301或者302HTTP时,自动拿转向的页面
curl_multi_add_handle ($mh,$conn[$url]);//关键,一定要放在上面几句之下,将单curl对象赋给多对象
}
//下面一大步的目的是为了减少cpu的无谓负担,暂时不明,来自php.net的建议,几乎是固定用法
do {
$mrc = curl_multi_exec($mh,$active);//当无数据时或请求暂停时,active=true
} while ($mrc == CURLM_CALL_MULTI_PERFORM);//当正在接受数据时
while ($active and $mrc == CURLM_OK) {//当无数据时或请求暂停时,active=true,为了减少cpu的无谓负担,这一步很难明啊
if (curl_multi_select($mh) != -1) {
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
}
/
//下面返回结果
foreach ($connomains as $i => $url) {
$cinfo=curl_getinfo($conn[$url]);//可用于取得一些有用的参数,可以认为是header
//$url=$cinfo[url];//真实url,有些url
if($killspace){//有点水消耗
$str=trim(curl_multi_getcontent($conn[$url]));
$str = preg_replace('//s(?=/s)/', '', $str);//去掉跟随别的挤在一块的空白
$str = preg_replace('/[/n/r/t]/', ' ', $str); //最后,去掉非space 的空白,用一个空格代替
$res[$url]=stripslashes($str);//取得对象源码,并取消换行,节约内存的同时,可以方便作正则处理
}else{
$res[$url]=curl_multi_getcontent($conn[$url]);
}
if(!$forhtml){//节约内存
$res[$url]=NULL;
}
/*下面这一段放一些高消耗的程序代码,用来处理HTML,我保留的一句=NULL是要提醒,及时清空对象释放内存,此程序在并发过程中如果源码太大,内在消耗严重
//事实上,这里应该做一个callback函数或者你应该将你的逻辑直接放到这里来,我为了程序可重复,没这么做
preg_match_all($preg,$res[$i],$matchlinks);
$res[$i]=NULL;
*/
curl_close($conn[$url]);//关闭所有对象
curl_multi_remove_handle($mh , $conn[$url]); //用完马上释放资源
}
curl_multi_close($mh);$mh=NULL;$conn=NULL;$connomains=NULL;
return $res;
}//cmi