最近我偶然发现了一个Parralel.For循环,为了我的目的,它比常规for循环更好。
这就是我使用它的方式:
Parallel.For(0, values.Count, i =>Products.Add(GetAllProductByID(values[i])));
它使我的应用程序工作更快,但仍然不够快。我向你们提出的问题是:
有人可以帮我解决这个问题吗?
答案 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
}