使用更多方法提高C#中Parallel.For的性能

时间:2016-10-24 15:15:24

标签: c# asp.net multithreading performance multiprocessing

最近我偶然发现了一个Parralel.For循环,为了我的目的,它比常规for循环更好。

这就是我使用它的方式:

Parallel.For(0, values.Count, i =>Products.Add(GetAllProductByID(values[i])));

它使我的应用程序工作更快,但仍然不够快。我向你们提出的问题是:

  1. Parallel.Foreach的执行速度是否快于Parallel.For?
  2. 是否有一些“混合”方法可以与我合并我的Parralel.For循环以更快地执行(即使用更多CPU功率)?如果是,怎么样?
  3. 有人可以帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

如果你想和平行播放,我建议使用 Parallel Linq PLinq )而不是Parallel.For / {{ 1}},例如

Parallel.ForEach

借助 var Products = Enumerable .Range(0, values.Count) .AsParallel() //.WithDegreeOfParallelism(10) // <- if you want, say 10 threads .Select(i => GetAllProductByID(values[i])) .ToList(); // <- this is thread safe now 方法(例如With),您可以尝试调整实施。

答案 1 :(得分:1)

有两个相关的概念:异步编程和多线程。基本上,要“并行”或异步地执行操作,您可以创建新线程或在同一线程上异步工作。

请记住,无论哪种方式,您都需要一些机制来阻止race conditions。从我链接的维基百科文章中,竞争条件定义如下:

  

竞争条件或种族危害是电子行为,   软件或其他系统,其输出取决于序列   或其他无法控制的事件的时间安排。事件发生时它就变成了一个bug   不要按程序员的意图发生。

正如一些人在评论中提到的那样,你不能依赖标准的List类来保证线程安全 - 即如果你从多个线程更新它,它可能会以意想不到的方式运行。 Microsoft现在提供了特殊的“内置”集合类(在System.Collections.Concurrent namespace中),如果您以异步方式或从多个线程更新它,它将以预期的方式运行。

对于记录良好的库(以及Microsoft在其文档中通常相当不错),文档通常会明确说明所讨论的类或方法是否是线程安全的。例如,在System.Collections.Generic.List的documentation中,它声明了以下内容:

  

此类型的公共static(在Visual Basic中为Shared)成员是thread   安全。不保证任何实例成员都是线程安全的。

在异步编程方面(与多线程相比),我对此的标准说明如下:假设你去了一个有10个人的餐馆。当服务员来的时候,他要求订购的第一个人还没准备好;然而,其他9人是。因此,服务员要求其他9个人的订单,然后回到原来的家伙。 (绝对不是这样的情况,他们会得到第二个服务员等待原来的人准备订购,这样做可能不会节省太多时间)。这就是异步/等待通常如何工作(例外,一些任务并行库调用,如Thread.Run(...),实际上正在其他线程上执行 - 在我们的插图中,引入了第二个服务员 - 所以确保你检查哪个文件是哪个。

基本上,您选择(在同一个线程上异步创建或创建新线程)取决于您是否尝试执行I / O绑定的操作(即您只是在等待操作完成或结果)或CPU绑定。

如果您的主要目的是等待Ebay的结果,那么在同一个线程中异步工作可能会更好,因为使用多线程可能无法获得很多性能优势。回想一下我们的比喻:引入第二个服务员只是为了等待第一个人准备订购,这不一定比让服务员回到他身边更好。

我不是坐在IDE的前面,如果这种语法不完美,请原谅我,但这里有一个关于你能做什么的近似想法:

public async Task GetResults(int[] productIDsToGet) {
    var tasks = new List<Task>();
    foreach (int productID in productIDsToGet) {
       Task task = GetResultFromEbay(productID);
       tasks.Add(task);
    }

    // Wait for all of the tasks to complete
    await Task.WhenAll(tasks);
}

private async Task GetResultFromEbay(int productIdToGet) {
    // Get result asynchronously from eBay
}