Curl多线程

本文详细介绍了PHP的CurlMulti库在多线程抓取、下载、链式任务等方面的应用,展示了如何利用CurlMulti实现高效稳定的网络请求。通过示例代码和性能测试,证明了该库在CPU占用、内存管理和带宽利用方面的优越性。
摘要由CSDN通过智能技术生成

Curl多线程

发表于2012 年 7 月 13 日

这个库是目前所有curl相关库中最强的,没有之一。

官网:
https://github.com/ares333/php-curlmulti

QQ群:215348766
1458616858207

工作中经常需要采集一些内容,所以深入研究了一下PHP CURL多线程,不得不说这个扩展很变态。经过几十次的修改终于写出一个完美的CURL类,有多厉害用“终极”二字形容也不为过。PHP文档中资料甚少,到网上也看到一些类,感觉实在太烂,有些类资源占用很高,有些稍微好点的效率真不敢恭维,说白了就是个原始的多线程而已,根本无法充分利用CPU和带宽。

 

本类的特点:
运行绝对稳定。
设置一个并发就会始终以这个并发数进行工作,即使通过回调函数添加任务也不影响。
CPU占用极低,绝大部分CPU消耗在用户的回调函数上。
内存利用率高,任务数量较多(15W个任务占用内存会超过256M)可以使用回调函数添加任务,个数自定。
能够最大限度的占用带宽。
链式任务,比如一个任务需要从多个不同的地址采集数据,可以通过回调一气呵成。
能够对CURL错误进行多次尝试,次数自定(大并发一开始容易产生CURL错误,网络状况或对方服务器稳定性也有可能产生CURL错误)。
回调函数相当灵活,可以多种类型任务同时进行(比如下载文件,抓取网页,分析404可以在一个PHP进程中同时进行)。
可以非常容易的定制任务类型,比如检查404,获取redirect的最后url等。
可以设置缓存,挑战产品节操。

不足:
不能充分利用多核CPU(可以开多个进程解决,需要自己处理任务分割等逻辑),可以用pthreads解决!
最大并发500(或512?),经过测试是CURL 内部限制,超过最大并发会导致总是返回失败。
目前没有断点续传功能。
目前任务是原子性的,不能对一个大文件分为几部分分别开线程下载。

我这里有34W张图片需要下载,先下载13W截图如下


每秒钟下载300张左右图片,每张图片300K左右,下载速度约100MB/s(1G的网卡用的差不多了),速度和下载文件总数有非常小的偏差,这个数值是根据CURL的传输字节数计算而来。速度超过100MB/s的时候SSH基本连接不上了。。。
iostat

主要瓶颈在IO上,否则速度会更快。

采集http://www.lyricsmode.com/的歌词速度也很快,一共60多万歌词页,平均每秒钟能稳定采集1200页(边采集边分析边入库,否则3000+页每秒都不稀奇),处理采集的HTML的速度根本追不上采集的速度,瓶颈应该是对方服务器速度,那个没有截图,有兴趣的可以试一下。

================================================================
完整文档如下
================================================================

尽可能展示类的特性。此demo环境是本机,所以性能不能达到最高,只做为使用说明,为了高性能请到服务器调试。选择http://www.1ting.com/作为目标站点,这个站比较典型,而且国内速度也很快。

本文用到两个类(这两个类在demo包中已经包含):
CUrl:多线程类。
PHPQuery:HTML分析,项目地址 http://code.google.com/p/phpquery/。如果google被封这里有较新版本 phpQuery-0.9.5.386.zip。这里用的压缩包中的 phpQuery/phpQuery.php这个单文件类,如果你不会用这个类没关系,用正则分析也可以。

必要的文件包含和初始化实例代码中都省略了。
代码非常完整,可以直接运行,demo请在命令行模式运行(你懂的)。
代码非常简洁。。。
PHPQuery需要php-dom扩展,PHP环境没有的话需要安装。
数据库操作使用PDO,所以也需要PDO扩展。
既然是demo,那么程序上我就一切从简了。
phpQuery很NB,很多变态的用法自己去研究吧,基本可以说无所不能。如果使用phpQuery必须在回调函数中手动调用phpQuery::unloadDocuments();释放,否则phpQuery处理的文档全部都在内存中!!!
并发情况可以用360的连接查看器查看。

CUrl一些必要内容:

  1. CUrl类单线程和多线程都可以使用缓存,并且缓存机制一样。
  2. CUrl类抓取HTML单线程和多线程返回的内容结构一致
    $result=array('info'=>array(),'content'=>'');
    $result['info']是curl_info()的内容,$result['content']是抓取的html文件。
  3. curl配置分为三个级别,优先级由低到高如下,优先级高的会覆盖优先级低的配置。
    默认:如私有方法init()中所示。
    类级别:保存在 $opt这个公有属性中,此CURL对象的所有操作中都会起作用。
    任务级别:多线程任务中添加任务时指定,只在当前任务中起作用。
  4. 类中用到回调函数的地方都使用call_user_func_array(),所以必须先从PHP手册中把这个函数搞明白了。

demo需要的数据表

01 CREATE TABLE `album` (
02   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
03   `artist_id` int(11) NOT NULL,
04   `namevarchar(255) NOT NULL,
05   `url` varchar(255) NOT NULL,
06   PRIMARY KEY (`id`)
07 ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
08  
09 CREATE TABLE `artist` (
10   `id` int(11) NOT NULL AUTO_INCREMENT,
11   `namevarchar(255) NOT NULL,
12   `pic` varchar(255) NOT NULL,
13   `url` varchar(255) NOT NULL,
14   PRIMARY KEY (`id`)
15 ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
16  
17 CREATE TABLE `songlist` (
18   `id` int(11) NOT NULL AUTO_INCREMENT,
19   `artist_id` int(11) NOT NULL,
20   `namevarchar(255) NOT NULL,
21   `album_url` varchar(255) NOT NULL,
22   PRIMARY KEY (`id`)
23 ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

压缩包中有程序运行的所有必要文件,导入curl.sql到test数据库,修改init.php中的配置就可以直接运行了!!
命令行:
php demo1.php
php demo2.php
php demo3.php
...
然后数据表中就有数据了。。。
demo中都没有phpQuery::unloadDocuments()操作,请自行加上。
windows命令行中文可能乱码导致非常奇怪的错误(尤其是demo5),windows命令行默认是GBK编码,可以php中用iconv转码,或修改命令行默认编码(没测试),所有代码在linux下测试完全正确。

完整Demo从此正式开始...

1.单线程用法

CUrl类有两个单线程的方法read(),download()。

1 $url='http://www.1ting.com/group/group0_2.html';
2 $result=$curl->read($url);
3 $html=phpQuery::newDocumentHTML($result['content']);
4 $li=$html['ul.allSinger li a'];
5 $st=$db->prepare("insert into artist(name,url) values(?,?)");
6 foreach($li as $v){
7     $v=pq($v);
8     $st->execute(array(trim($v->text()),trim($v->attr('href'))));
9 }

用单线程方法抓取女歌手列表页,用PHPQuery进行分析,取出歌手名子和详情页地址并存入artist表,本次示例抓取了2417个歌手。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值