CURL多线程抓取网页

网上这类方法似乎太多了。但是总是有一些问题存在。。。

 

对于多线程抓取,现在有如下几种思路:

1.用apache的多线程特性,让php进行“多进程”操作,就像post本身一样

2.用curl的curl_multi库

 

对于第一种,我还没尝试,因为这种制造的是伪多线程,也许效率会低很多,而且不好控制。

第二种我尝试了,大概内容是这样的:

 

define("DELAY_TIME",10000); function multiget($urls) { $multi_handle=curl_multi_init(); foreach ($urls as $i => $url) { $conn[$i]=curl_init($url); curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1); $timeout = 3; curl_setopt($conn[$i], CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt ($conn[$i], CURLOPT_FOLLOWLOCATION, 1); curl_multi_add_handle($multi_handle,$conn[$i]); } //下面一大步的目的是为了减少cpu的无谓负担,暂时不明,来自php.net的建议,几乎是固定用法 do { $mrc = curl_multi_exec($multi_handle,$active);//当无数据时或请求暂停时,active=true } while ($mrc == CURLM_CALL_MULTI_PERFORM);//当正在接受数据时 while ($active and $mrc == CURLM_OK) {//当无数据时或请求暂停时,active=true,为了减少cpu的无谓负担,这一步很难明啊 if (curl_multi_select($multi_handle) != -1) { do { $mrc = curl_multi_exec($multi_handle, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } } /* 这是另外一种写法,会使CPU占用率始终100%,增加usleep稍微好点 do { $mrc = curl_multi_exec($multi_handle,$active); usleep (DELAY_TIME); } while ($active); */ //依次提取连接内容 foreach ($urls as $i => $url) { $contents[$i]=curl_multi_getcontent($conn[$i]); curl_multi_remove_handle($multi_handle,$conn[$i]); curl_close($conn[$i]); } return $contents; } 

其它的不多说,只说do while的那一块。

那一块的功能就是不停地等待,直到所有线程都结束。

而这种等待因为没有消息机制,所以只能靠不停地判断来消耗时间(方式B),同时导致 CPU的大量占用,然后就发明了那个注释很多的方法。

 

方式A的优点就是CPU占用小,具体原理不明。。。。

 

但是经过实际测试,出现如下结果:

测试环境:访问校内网站某信息页面1000个,100M校园网,网络状况良好,每个页面只有几KB

电脑:台式机,phenom x3 720 2.80GHZ*3

 

如果使用curl单线程的话,耗时24秒;

当使用多线程时,情况如下:

【方式B】

每2网页处理一次:14秒

每10网页处理一次:9.8秒

每100网页处理一次:9.8秒

每999网页处理一次:读不出数据了- -

可见多线程可以大大提高读取速度,当到10线程的时候,已经到极限了,已经把网络延迟降低到最小了。。。

 

【方式A】

每10网页处理一次  >30秒

每100网页处理一次  :21秒

每200网页处理一次:14秒

每300网页处理一次:12.9秒

每500网页处理一次:8.3秒,但是显示不出来网页了。。。。

 

可见A方式在处理大量线程(上百个)时有巨大优势,但是在这种条件下仍然不是最快的。。。

可能需要更大的数据?

 

结合未来使用情况,批量抓取网页只是每几分钟一次,而且不存在N用户同时多线程抓取的,但是处理时间其实已经很接近了……所以现在还没想好用哪个- -从健康讲似乎A方式更好一点,虽然会慢那么一点点。。。。

 

下次测试一下POST方式再说吧~

你可能感兴趣的:(PHP)