C#多线程质量分析

时间:2013-05-14 17:43:35

标签: c# multithreading

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

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

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

基本上,我正在寻找有人使用多线程为我指出正确的效率方向,这样我就可以节省解析我最终的那些页面所需的时间,某种系统或结构用于线程化。

由于

2 个答案:

答案 0 :(得分:7)

查看this问题的答案,因为您可能想要查看Parallel.ForEach

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

  1. 下载LINQPad。 (应该是任何C#开发人员的先决条件,imho!)
  2. 在“样本”,“下载/导入更多样本......”中,确保已下载“C#中的异步函数”。
  3. 查看样本,了解它们如何组合在一起。
  4. 实际上,这是与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!
    

答案 1 :(得分:2)

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

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

每个线程将使用大约1MB的堆栈空间,这意味着你将使用大约1千兆的资源。但实际上,如果你创建1000个线程,处理很可能比仅使用一个线程。通常每个核心/处理器1个线程。因此,四核/四核处理器一开始就是一个很好的线程计数是16,你可以根据你的程序正在做什么,如果你想要覆盖库的工作方式或者自己动手来调高它。 。但我不建议这样做,因为图书馆可以自动为你处理这些内部工作。

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