我需要从网站上抓取数据。 我需要访问超过1,000个链接,之前我正在为每个线程划分10个链接,并且每个线程都会启动100个线程。在几个测试用例之后,100个线程是最小化检索内容的时间的最佳计数所有的链接。
我意识到.NET 4.0为开箱即用的多线程提供了更好的支持,但这是基于你拥有多少核心来完成的,在我的情况下,它不会产生足够的线程。我想我要问的是:什么是优化1,000链路拉动的最佳方法。我是否应该使用.ForEach
并让Parallel
扩展控制产生的线程数量,或者找到一种方法来告诉它要启动多少线程并划分工作?
我之前没有和Parallel
合作过,所以也许我的做法可能不对。
答案 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上的请参阅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>)