通过curl库的curl_multi方法实现并发请求多个URL

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

 

curlcurl_multi都是用于进行网络请求的工具。 curl是一个命令行工具,可以通过发送HTTP请求来获取网页内容或发送其他类型的网络请求。它是单线程的,在发送一个请求时会阻塞程序的执行直到请求完成并返回结果。这意味着如果要进行高并发请求,需要启动多个curl进程来同时发送多个请求,但会造成系统资源的浪费。 而curl_multi是一个C语言,可以实现多个网络请求并发执行。它通过将多个curl实例放入一个集合中,并使用事件循环来处理多个请求的同时执行。这样,在发送一个请求时,程序不会阻塞,而是可以继续执行其他任务,提高了并发处理能力。当所有的请求都完成时,可以一次性获取所有的结果。这种方式减少了系统资源的浪费,提高了程序的效率。 使用curl_multi进行高并发需要注意以下几点: 1. 创建curl_multi实例,并向其中添加需要执行的curl请求。 2. 使用curl_multi_exec函数来开始执行多个请求。 3. 使用curl_multi_select函数等待请求完成。 4. 使用curl_multi_getcontent函数获取每个请求的结果。 需要注意的是,高并发的网络请求对服务器压力较大,也容易出现网络超时等问题,因此需要合理控制并发请求数量,使用适当的技术手段,如连接池、负载均衡等,来保证系统的稳定性和性能。 总之,curlcurl_multi都可以用于高并发的网络请求,但curl_multi具有更好的并发性能和资源利用率,适合在程序中进行大量请求的同时执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值