【问题标题】:C# Multithreaded Mass ParseC# 多线程批量解析
【发布时间】:2013-05-14 17:43:35
【问题描述】:

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

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

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

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

谢谢

【问题讨论】:

  • 您知道所有 300,000 个链接一开始就知道,还是在您进行操作时发现它们?
  • 查看更高级别的 .NET 多线程概念,例如 async 和任务并行库。
  • @jon - 我知道所有 300,000 个链接一开始,所以它不是一个真正的爬虫,只是一个解析器。
  • 听起来Parallel.ForEach 是你的朋友。您应该了解您的网站准备处理的流量。

标签: c# multithreading


【解决方案1】:

查看this 问题的答案,听起来您可能想查看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!

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-05-21
      • 2012-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      • 2022-01-14
      • 2015-12-16
      相关资源
      最近更新 更多