最好地使用Parallel.ForEach / Multithreading

时间:2013-02-08 16:47:49

标签: c# .net multithreading parallel.foreach

我需要从网站上抓取数据。 我需要访问超过1,000个链接,之前我正在为每个线程划分10个链接,并且每个线程都会启动100个线程。在几个测试用例之后,100个线程是最小化检索内容的时间的最佳计数所有的链接。

我意识到.NET 4.0为开箱即用的多线程提供了更好的支持,但这是基于你拥有多少核心来完成的,在我的情况下,它不会产生足够的线程。我想我要问的是:什么是优化1,000链路拉动的最佳方法。我是否应该使用.ForEach并让Parallel扩展控制产生的线程数量,或者找到一种方法来告诉它要启动多少线程并划分工作?

我之前没有和Parallel合作过,所以也许我的做法可能不对。

4 个答案:

答案 0 :(得分:4)

通常,Parallel.ForEach()非常擅长优化线程数。它考虑了系统中的核心数量,但也考虑了线程正在做什么(CPU绑定,IO绑定,方法运行的时间等)。

您可以控制最大并行度,但没有强制使用更多线程的机制。

确保您的基准测试是正确的,并且可以以公平的方式进行比较(例如,相同的网站,在开始测量之前允许预热期,并且由于响应时间变化可能是相当高的抓取网站,所以进行多次运行)。如果经过仔细测量后,您自己的线程代码仍然更快,您可以得出结论,您已经针对特定情况优化了.NET,并坚持使用自己的代码。

答案 1 :(得分:4)

您可以在Parallel.ForEach中使用MaxDegreeOfParallelism属性来控制将要生成的线程数。

下面是代码段 -

ParallelOptions opt = new ParallelOptions();
opt.MaxDegreeOfParallelism = 5;

Parallel.ForEach(Directory.GetDirectories(Constants.RootFolder), opt, MyMethod);

答案 2 :(得分:3)

值得一试的是TPL Dataflow库。

MSDN上的

DataFlow

请参阅Nesting await in Parallel.ForEach

  

Parallel.ForEach()背后的整个想法是你有一组线程,每个线程都处理集合的一部分。正如您所注意到的,这不适用于async-await,您希望在异步调用期间释放该线程。

此外,演练Creating a Dataflow Pipeline专门设置和处理多个网页下载。 TPL Dataflow确实是为这种情况设计的。

答案 3 :(得分:0)

很难说没有查看您的代码以及如何定义集合,我发现Parallel.Invoke是最灵活的。试试msdn? ......听起来你正在使用Parallel.For Method (Int32, Int32, Action<Int32, ParallelLoopState>)