0

我有用 C# 编写的 Webcrawles,它使用多线程。现在它可以下载和解析大约 1000 个链接/分钟,但是当我运行 ex. 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 磁盘

4

6 回答 6

3

在 URL 列表上使用的问题Parallel.ForEach在于,这些列表通常包含来自同一站点的许多 URL,并且您最终会收到对同一站点的多个并发请求。一些网站对此不屑一顾,会阻止您或人为延迟。

每分钟 1,000 个请求相当于每秒 16 或 17 个请求,这几乎是您在不采取特殊措施的情况下所能做到的极限。问题的很大一部分是 DNS 解析,这可能需要非常长的时间。此外,默认的 .NETServicePointManager将您限制为在任何给定站点上的 2 个并发请求。如果您想支持更多,您需要更改ServicePointManager.DefaultConnectionLimit属性。

您绝对不想添加数百个线程。我做过一次。这是痛苦的。你需要的是一些可以非常快速地发出异步请求的线程。我的测试表明,单个线程每秒不能支持超过 15 个请求,因为HttpRequest.BeginGetResponse在异步之前做了很多同步工作。正如文档所述:

BeginGetResponse 方法需要在此方法变为异步之前完成一些同步设置任务(例如 DNS 解析、代理检测和 TCP 套接字连接)。

您可以通过增加 DNS 客户端缓存的大小并在单独的计算机上拥有本地 DNS 缓存来加快速度,但您可以在那里实现的目标是有限的。

不知道你爬了多少。如果您做了很多事情,那么您需要实施一项礼貌政策,考虑到 robots.txt 文件,限制它访问特定站点的频率,限制它下载的 URL 类型(下载 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/。这是我一直想回到的东西,但近两年后我仍然没有做到。

您还会遇到代理问题、URL 过滤问题(此处此处)、奇怪的重定向以及不完全异步的异步调用

于 2013-10-21T22:08:00.330 回答
1

您不需要更多线程,因为这些线程都在等待。你需要一个异步程序,它不会阻塞等待网络回复的线程。

线程的问题在于它们是一种相当昂贵的资源,因为它们的堆栈需要内存,以及它们为 OS 线程调度程序创建的工作。在您的程序中,此调度程序不断将线程切换到它们都可以轮流等待的状态。但他们没有做任何有用的事情。

于 2013-10-21T12:45:34.203 回答
0

实际上每分钟的链接数与同时运行的爬虫线程数成正比。

在您的第一种情况下;你有 3 个进程,每个进程有 n 个线程。(总共 3n 个线程)

尝试在一个进程中运行 3n 个线程。

实际上,这也取决于您的操作系统和 CPU。因为旧版本的 Windows(如 XP)不支持不同 cpu 内核上的并行多线程。

于 2013-10-21T12:39:26.457 回答
0

在网络爬虫中,您将花费大部分时间等待网络请求。因此,如果您有阻塞 I/O,您的程序将不会全速处理,如果程序处于空闲状态等待回调,异步 IO 也无济于事。听起来您只需要向主应用程序添加更多线程并并行处理。

但很难说,因为你没有发布任何代码。,

于 2013-10-21T12:35:22.573 回答
0

与 TPL 的并行性对于网络爬虫来说是糟糕的设计。Parallel.ForEach() 循环仅启动一堆请求(5-50),因为它旨在并行执行耗时的计算,而不是并行执行数千个几乎什么都不做的请求。要获得您想要的数据,您必须能够并行执行大量(10000+)个请求。异步操作是其中的关键。

我开发了 Crawler-Lib 框架的 Crawler Engine。它是一个支持工作流的爬虫,可以轻松扩展以执行任何类型的请求,甚至处理您想要的处理。它旨在为您提供开箱即用的高吞吐量。

这是引擎:http ://www.crawler-lib.net/crawler-lib-engine

以下是一些 Youtube 视频,展示了 Crawler-Lib 引擎的工作原理:http ://www.youtube.com/user/CrawlerLib

我知道这个项目不是开源的,但是有一个免费版本。

于 2013-12-28T09:04:34.073 回答
0

是的。找出你的瓶颈在哪里并提高性能。

编辑:

如果您使用的是 Parallel.ForEach,您可以使用ParallelOptions参数尝试重载。设置 MaxDegreeOfParallelism 属性可能会有所帮助。

于 2013-10-21T12:24:20.357 回答