您的“问题”是在没有意义的情况下使用 PLINQ
PLINQ 并不总是更快。PLINQ 总是会增加开销。
在 CPU 指令方面;无论您需要做多少工作(称为 X),您最终都会执行超过 X 条指令。PLINQ 将做很多额外的工作来启动线程,将工作委派给它们并将结果返回到您可以使用的形式中。
这样做的好处是您可以让多个 CPU/Core 工作。有时它更快。当您正在执行的 CPU 工作量相对于开销而言较小时,它会变慢。
当我运行您的代码时,我得到以下输出:
顺序执行 2 毫秒
并行执行 40 毫秒
我还可以看到PLINQ 代码创建了八个工作线程。这八个线程代表了 2 毫秒计算的大量开销。您可以通过运行 Parallel Execution 基准测试两次来了解它的开销。工作线程将徘徊。这是我第二次运行它的输出:
顺序执行 2 毫秒
并行 #1 执行 40 毫秒
并行 #2 执行 3 毫秒
第二次要快得多;但仍然比什么都不做要慢。因为,即使已经创建了工作线程 - PLINQ 仍然需要做一些工作来划分线程之间的操作并以您可以访问的格式返回结果。
你要做的工作越多,开销的影响就越小。在此示例中,我已将您的 Where lambda 替换为调用的静态函数IsValid
,并且我计算了 %2 500 次,而不是仅计算一次。
static bool IsValid(int input)
{
int result=0;
for(int i =0;i<500;i++)
result = input%2;
return result == 0;
}
现在 - 我的执行时间是:
顺序执行 36 毫秒
并行 #1 执行 47 毫秒
并行 #2 执行 9 毫秒
您可以看到 PLINQ 在第一次执行时仍然较慢 - 但在第二次执行时明显更快。如果您通过将循环从 500 增加到 5000(在我的机器上)来提高 CPU 工作量,那么 PLINQ 获胜,请放下手。
TL;DR - 你做得对;您只是没有做足够的工作使 PLINQ 成为更快的选择。
这是我所做的整个源代码:
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
int[] vals = Enumerable.Range(0, Int16.MaxValue).ToArray();
sw.Start();
int[] x1 = vals.Where(IsValid).ToArray();
sw.Stop();
Console.WriteLine("Sequential Execution {0} milliseconds", sw.ElapsedMilliseconds);
sw.Restart();
int[] x2 = vals.AsParallel().Where(IsValid).ToArray();
sw.Stop();
Console.WriteLine("Parallel #1 Execution {0} milliseconds", sw.ElapsedMilliseconds);
sw.Restart();
int[] x3 = vals.AsParallel().Where(IsValid).ToArray();
sw.Stop();
Console.WriteLine("Parallel #2 Execution {0} milliseconds", sw.ElapsedMilliseconds);
Console.Read();
}
static bool IsValid(int input)
{
int result=0;
for(int i =0;i<5000;i++)
result = input%2;
return result == 0;
}