改进并行的性能.在c#中有更多的方法

本文关键字:方法 并行 性能 | 更新日期: 2023-09-27 18:14:34

最近我偶然发现了一个并行程序。对于我来说,For循环比常规的For循环要好得多。

我是这样使用的:

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

它使我的应用程序工作得更快,但仍然不够快。我的问题是:

  1. 是平行的。Foreach比Parallel.For?
  2. 是否有一些"混合"方法,我可以结合我的并行。For循环执行得更快(即使用更多的CPU功率)?如果是,怎么做?
有人能帮我一下吗?

改进并行的性能.在c#中有更多的方法

如果你想与并行,我建议使用 parallel Linq (PLinq)而不是Parallel.For/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方法(例如WithDegreeOfParallelism)的帮助下,您可以尝试调整您的实现

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

请记住,无论哪种方式,您都需要一些机制来防止竞争条件。从我链接到的Wikipedia文章中,竞态条件的定义如下:

竞态条件或竞态危险是电子设备的行为,输出依赖于序列的软件或其他系统或者其他不可控事件的时间安排。当事件发生时,它就变成了一个bug不要按程序员想要的顺序发生。

正如一些人在评论中提到的,你不能依赖标准的List类是线程安全的——也就是说,如果你从多个线程更新它,它可能会以意想不到的方式运行。微软现在提供了特殊的"内置"集合类(在System.Collections.Concurrent命名空间中),如果你异步更新它或从多个线程更新它,它将以预期的方式运行。

对于文档完备的库(微软在其文档中通常对此做得很好),文档通常会显式地说明所讨论的类或方法是否线程安全。例如,在System.Collections.Generic的文档中。列表中,它声明如下:

Public static(在Visual Basic中共享)这种类型的成员是thread安全的。不能保证任何实例成员都是线程安全的。
关于异步编程(相对于多线程),我的标准说明如下:假设你和10个人一起去一家餐馆。当服务员经过时,他问的第一个人还没有准备好;然而,另外9个人是。因此,服务员向其他9个人要了他们的菜,然后又回到原来的那个人那里。(他们绝对不会再找一个服务员来等原来的服务员来点餐,而且这样做可能也不会节省多少时间)。这就是async/await的典型工作方式(例外的是,一些任务并行库调用,比如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
}