3

我正在制作一个“网络解析器”,除了它只用于 1 个网站,它将同时解析许多不同的页面。

目前,我可能需要以相对较快的方式解析 300,000 个页面(我只抓取少量不需要太长时间的信息,每个页面最多需要大约 3 秒网络)。当然,900,000 秒到天 = 10 天,这是很糟糕的表现。我最多希望将其减少到几个小时,我对请求数量的时间是合理的,但它仍然需要“快速”。我也知道我不能一次只做 300,000 个,否则网站会阻止我所有的请求,所以每个请求之间必须有几秒钟的延迟。

我目前在单个 foreach 循环中处理它,没有利用任何多线程,但我知道我可以利用它,我不确定我应该采取什么路径,无论是线程池还是其他螺纹系统或设计的类型。

基本上,我正在寻找使用多线程来为我指出正确的效率方向的人,以便我可以减少解析那么多页面所需的时间,某种系统或线程结构。

谢谢

4

2 回答 2

7

查看问题的答案,因为听起来您可能想查看Parallel.ForEach.

还有各种其他方法可以以多线程方式实现您想要做的事情。为了让自己了解这是如何工作的:

  1. 下载LINQPad。(应该是任何 C# 开发人员的先决条件,恕我直言!)
  2. 在“示例”中,“下载/导入更多示例...”并确保您已下载“C# 中的异步函数”。
  3. 研究这些样本,看看它们是如何组合在一起的。

事实上,这里是使用 Uris 的异步示例之一:

// The await keyword is really useful when you want to run something in a loop. For instance:

string[] uris =
{
    "http://linqpad.net",
    "http://linqpad.net/downloadglyph.png",
    "http://linqpad.net/linqpadscreen.png",
    "http://linqpad.net/linqpadmed.png",
};

// Try doing the following without the await keyword!

int totalLength = 0;
foreach (string uri in uris)
{
    string html = await (new WebClient().DownloadStringTaskAsync (new Uri (uri)));
    totalLength += html.Length;
}
totalLength.Dump();

// The continuation is not just 'totalLength += html.Length', but the rest of the loop! (And that final
// call to 'totalLength.Dump()' at the end.)

// Logically, execution EXITS THE METHOD and RETURNS TO THE CALLER upon reaching the await statement. Rather
// like a 'yield return' (in fact, the compiler uses the same state-machine engine to rewrite asynchronous
// functions as it does iterators).
//
// When the task completes, the continuation kicks off and execution jumps back into the middle of the 
// loop - right where it left off!
于 2013-05-14T17:49:29.367 回答
2

正如其他人提到的那样,使用并行处理可以帮助您入门。使用 .Net 4.0 或更高版本,它可以直接使用,并且非常易于使用。如果您有一个 foreach 循环并想要添加并行化,只需添加对的引用system.threading并添加Parallel.ForEach. 请记住,生成的线程数量没有限制,但存在实际限制。内置的 .Net 库为您屏蔽细节并自动为您管理线程池。

如果您决定更改参数,请记住以下几点:

每个线程将使用大约 1MB 的堆栈空间,这意味着每千人将使用大约 1 Gig 的资源。但实际上,如果您创建 1000 个线程,处理很可能会比仅使用一个线程慢。通常每个核心/处理器 1 个线程。因此,四核/四核处理器的一个好的线程数从 16 个开始,如果您想覆盖库的执行方式或自己滚动,您可以根据程序正在做什么来调整它. 但我不建议这样做,因为该库可以很好地自动为您处理这些内部结构。

我还要提一下,一台机器可能无法满足您的需求,因此您的应用程序应该水平扩展,并且能够添加新机器并解析更多页面,而不仅仅是一台机器(多线程或其他)。

于 2013-05-14T18:06:06.580 回答