我在C#中编写Webcrawles,它使用多线程。现在它可以下载和解析大约1000个链接/分钟,但是当我运行前。 3个实例同时每个实例可以达到1000个链接/分钟,所以我有3000个链接/分钟。一个实例使用高达2%的CPU,100MB RAM和1%的网络速度。现在我想知道当我拥有可用资源(cpu,ram,network)时,一个实例可以达到3000个链接/分钟或更多?
我的代码结构:
ThreadSafeFileBuffer<string> successWriter = new ThreadSafeFileBuffer<string>("ok.txt");
IEnumerable<string> lines = File.ReadLines("urls.txt");
var options = new ParallelOptions
{
CancellationToken = _cts.Token,
MaxDegreeOfParallelism = 500
};
Parallel.ForEach(lines, options, (line, loopState, idx) =>
{
var crawler = new Crawler(line);
var result = crawler.Go(); //download,parse
successWriter.AddResult(result);
}
我有Windows 7,CPU i7,16GB RAM,SSD磁盘
答案 0 :(得分:3)
在网址列表中使用Parallel.ForEach
的问题是,这些列表通常包含来自同一网站的多个网址,并且您最终会向同一网站发送多个并发请求。一些网站对此不以为然,会阻止您或插入人为延迟。
每分钟1,000个请求每秒可处理16或17个请求,这几乎是您在不采取特殊措施的情况下可以做到的限制。问题的很大一部分是DNS解析,这可能需要很长时间。此外,默认的.NET ServicePointManager
将您限制为任何给定站点上的2个并发请求。如果您想支持更多,则需要更改ServicePointManager.DefaultConnectionLimit属性。
你绝对不想添加数百个线程。我做过一次。这是痛苦的。您需要的是一些可以非常快速地发出异步请求的线程。我的测试表明,单个线程每秒不能支持超过15个请求,因为HttpRequest.BeginGetResponse在异步之前执行了大量的同步工作。正如文档所述:
在此方法异步之前,BeginGetResponse方法需要完成一些同步设置任务(例如DNS解析,代理检测和TCP套接字连接)。
您可以通过增加DNS客户端缓存的大小以及在单独的计算机上使用本地DNS缓存来加快速度,但是您可以在那里实现的目标有限制。
我不知道你正在做多少爬行。如果你做了很多,那么你需要实现一个礼貌政策,该政策考虑到robots.txt文件,限制它访问特定网站的频率,限制它下载的网址类型(无需下载MP3或。 doc文件,如果你不能对它做任何事情,例如)等。为了防止你的抓取工具被阻止,你的抓取工具成为一个礼貌政策执行者的核心,恰好下载网页。
我开始写这段时间,但后来没有完成(其他项目优先)。有关第一篇文章,请参阅http://blog.mischel.com/2011/12/13/writing-a-web-crawler-introduction/,并链接到该主题中的其他帖子。另请参阅http://blog.mischel.com/2011/12/26/writing-a-web-crawler-queue-management-part-1/。这是我一直想要回归的东西,但差不多两年后我仍然没有管理它。
您还会遇到proxy problems,网址过滤问题(here和here),weird redirects和asynchronous calls that aren't completely asynchronous。
答案 1 :(得分:1)
您不需要更多线程,因为这些线程都会花时间等待。您需要一个异步程序,它不会阻止等待Web回复的线程。
线程的问题在于它们是一个相当昂贵的资源,因为它们的堆栈需要内存,以及它们为OS线程调度程序创建的工作。在您的程序中,此调度程序继续切换线程,以便它们可以轮流等待。但他们没有做任何有用的事情。
答案 2 :(得分:0)
是的,确实如此。找出瓶颈在哪里并改善性能。
编辑:
如果您使用的是Parallel.ForEach,则可以使用ParallelOptions参数尝试重载。设置MaxDegreeOfParallelism属性可能会有所帮助。
答案 3 :(得分:0)
在网络浏览器中,您将花费大部分时间等待网络请求。因此,如果您有阻塞I / O,您的程序将无法全速处理,如果程序空闲等待回调,async IO也无法提供帮助。听起来你只需要在主应用程序中添加更多线程并进行并行处理。
但很难说,因为你没有发布任何代码。
答案 4 :(得分:0)
实际上,链接数/ min与同时运行的爬虫线程数成正比。
在你的第一个案件中;你有3个进程,每个n个线程。 (总共3n个线程)
尝试在一个进程中运行3n个线程。
实际上这也取决于您的操作系统和CPU。因为旧版本的Windows(如XP)不支持在不同的cpu核心上进行并行多线程处理。
答案 5 :(得分:0)
与TPL的并行性是网络爬虫的糟糕设计。 Parallel.ForEach()循环仅启动一堆请求(5-50),因为它旨在并行执行耗时的计算,而不是并行执行数千个请求,几乎不执行任何操作。要获得您想要的数据,您必须能够并行执行大量(10000+)以上的请求。异步操作是关键。
我开发了Crawler-Lib Framework的Crawler Engine。它是一个支持工作流的爬虫,可以轻松扩展以执行任何类型的请求,甚至可以进行处理。 它旨在为您提供开箱即用的高吞吐量。
以下是引擎:http://www.crawler-lib.net/crawler-lib-engine
以下是一些Youtube视频,展示了Crawler-Lib引擎的工作原理:http://www.youtube.com/user/CrawlerLib
我知道这个项目不是开源的,但有一个免费版本。