我正在构建一个简单的LinQ-to-object查询,我想并行化,但是我想知道语句的顺序是否重要?
e.g。
IList<RepeaterItem> items;
var result = items
.Select(item => item.FindControl("somecontrol"))
.Where(ctrl => SomeCheck(ctrl))
.AsParallel();
VS。
var result = items
.AsParallel()
.Select(item => item.FindControl("somecontrol"))
.Where(ctrl => SomeCheck(ctrl));
会有什么不同吗?
答案 0 :(得分:23)
绝对。在第一种情况下,投影和过滤将按顺序进行,只有然后才能并行化。
在第二种情况下,投影和过滤都将并行发生。
除非你有特别的理由使用第一个版本(例如投影具有线程亲和力或其他一些奇怪的东西),你应该使用第二个版本。
编辑:这是一些测试代码。有许多基准测试存在缺陷,但结果是合理的结论:
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
class Test
{
static void Main()
{
var query = Enumerable.Range(0, 1000)
.Select(SlowProjection)
.Where(x => x > 10)
.AsParallel();
Stopwatch sw = Stopwatch.StartNew();
int count = query.Count();
sw.Stop();
Console.WriteLine("Count: {0} in {1}ms", count,
sw.ElapsedMilliseconds);
query = Enumerable.Range(0, 1000)
.AsParallel()
.Select(SlowProjection)
.Where(x => x > 10);
sw = Stopwatch.StartNew();
count = query.Count();
sw.Stop();
Console.WriteLine("Count: {0} in {1}ms", count,
sw.ElapsedMilliseconds);
}
static int SlowProjection(int input)
{
Thread.Sleep(100);
return input;
}
}
结果:
Count: 989 in 100183ms
Count: 989 in 13626ms
现在PFX中有许多启发式的东西,但很明显第一个结果根本没有并行化,而第二个结果已经。
答案 1 :(得分:1)
这很重要,而不仅仅是在表现上。
第一个和第二个查询的结果不相等。
有解决方案可以进行并行处理并保持原始顺序。
使用AsParallel().AsOrdered()
。第三个查询显示它。
var SlowProjection = new Func<int, int>((input) => { Thread.Sleep(100); return input; });
var Measure = new Action<string, Func<List<int>>>((title, measure) =>
{
Stopwatch sw = Stopwatch.StartNew();
var result = measure();
sw.Stop();
Console.Write("{0} Time: {1}, Result: ", title, sw.ElapsedMilliseconds);
foreach (var entry in result) Console.Write(entry + " ");
});
Measure("Sequential", () => Enumerable.Range(0, 30)
.Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Parallel", () => Enumerable.Range(0, 30).AsParallel()
.Select(SlowProjection).Where(x => x > 10).ToList());
Measure("Ordered", () => Enumerable.Range(0, 30).AsParallel().AsOrdered()
.Select(SlowProjection).Where(x => x > 10).ToList());
结果:
Sequential Time: 6699, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Parallel Time: 1462, Result: 12 16 22 25 29 14 17 21 24 11 15 18 23 26 13 19 20 27 28
Ordered Time: 1357, Result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
我对此感到很惊讶,但是在10+测试运行后结果是一致的。我调查了一下,结果证明是.Net 4.0中的“bug”。在4.5 AsParallel()并不比AsParallel()慢.AsOrdered()
参考文献在这里:
http://msdn.microsoft.com/en-us/library/dd460677(v=vs.110).aspx