为什么这个并行代码比类似的非并行版本慢?
Why is this parallel code slower than its similar non parallel version?
我有以下代码(从 LINQPad 复制到这里)。显然我不明白 TPL 是如何工作的或者代码是垃圾,为什么并行版本 运行 比非并行版本慢?
for (int i = 0; i < 100; i++)
{
ParallelOptions ops = new ParallelOptions();
ops.MaxDegreeOfParallelism = Environment.ProcessorCount;
var watch = Stopwatch.StartNew();
Parallel.ForEach<int>(Enumerable.Range(1, 10000000), ops, x => { int y = x + 1; });
watch.Stop();
Console.WriteLine("Parallel: {0}", watch.Elapsed.TotalSeconds);
watch = Stopwatch.StartNew();
foreach (var x in Enumerable.Range(1, 10000000))
{
int y = x + 1;
}
watch.Stop();
Console.WriteLine("Non-parallel: {0}\n", watch.Elapsed.TotalSeconds);
}
前 10 个结果:
平行:0.1991644
非平行:0.0466178
平行:0.1723428
非平行:0.0447134
平行:0.1141791
非平行:0.0444557
平行:0.1758878
非平行:0.0444636
平行:0.1687637
非平行:0.0444338
平行:0.1677679
非平行:0.0445771
平行:0.1191462
非平行:0.0446116
平行:0.1702483
非平行:0.0454863
平行:0.1143605
非平行:0.0451731
平行:0.2155218
非平行:0.0450392
好吧,您可以获得的最佳答案是 运行 分析器工具并衡量您的代码发生了什么。但我有根据的猜测是,您的并行代码速度较慢,因为您的代码非常简单,以至于启动线程和在线程之间切换会增加如此多的成本,以至于计算速度方面的任何优势都可以忽略不计。
但是尝试进行一些实质性的计算,您最终将拥有并行执行的优势。你的代码太简单了。现代 CPU 不会以这种方式加载。
由于我无法将其添加为评论,因此我将对 post 修改后的代码添加另一个答案。 @ixSci 在他的回答中所说的似乎是正确的。我在执行速度非常快的并行代码体中执行了一个微不足道的操作,但是速度慢的原因是大量时间花在了线程之间的上下文切换上?当我将代码更改为休眠一段时间而不是将 int 值增加 1 时,并行代码大约比非并行版本快 4 倍(我的 CPU 中的内核数)。
for (int i = 0; i < 100; i++)
{
ParallelOptions ops = new ParallelOptions();
ops.MaxDegreeOfParallelism = Environment.ProcessorCount;
var partitioner = Partitioner.Create<int>(Enumerable.Range(1, 5000));
var watch = Stopwatch.StartNew();
Parallel.ForEach<int>(partitioner, ops, x => { Thread.Sleep(1); });
watch.Stop();
Console.WriteLine("Parallel: {0}", watch.Elapsed.TotalSeconds);
watch = Stopwatch.StartNew();
foreach (var x in Enumerable.Range(1, 5000))
{
Thread.Sleep(1);
}
watch.Stop();
Console.WriteLine("Non-parallel: {0}\n", watch.Elapsed.TotalSeconds);
}
前 10 个结果:
平行:1.2887589
Non-parallel: 5.0020569
平行:1.277047
Non-parallel: 5.0011116
平行:1.2790631
Non-parallel: 5.0001498
平行:1.2770644
Non-parallel: 5.0052016
平行:1.2770013
Non-parallel: 5.0021479
平行:1.2770031
Non-parallel: 5.0001927
平行:1.2799937
Non-parallel: 5.0062141
平行:1.2819909
Non-parallel: 5.0171945
平行:1.2780496
Non-parallel: 5.0071667
平行:1.2821714
Non-parallel: 5.0082108
平行:1.2777875
Non-parallel: 5.0152099
我有以下代码(从 LINQPad 复制到这里)。显然我不明白 TPL 是如何工作的或者代码是垃圾,为什么并行版本 运行 比非并行版本慢?
for (int i = 0; i < 100; i++)
{
ParallelOptions ops = new ParallelOptions();
ops.MaxDegreeOfParallelism = Environment.ProcessorCount;
var watch = Stopwatch.StartNew();
Parallel.ForEach<int>(Enumerable.Range(1, 10000000), ops, x => { int y = x + 1; });
watch.Stop();
Console.WriteLine("Parallel: {0}", watch.Elapsed.TotalSeconds);
watch = Stopwatch.StartNew();
foreach (var x in Enumerable.Range(1, 10000000))
{
int y = x + 1;
}
watch.Stop();
Console.WriteLine("Non-parallel: {0}\n", watch.Elapsed.TotalSeconds);
}
前 10 个结果:
平行:0.1991644 非平行:0.0466178
平行:0.1723428 非平行:0.0447134
平行:0.1141791 非平行:0.0444557
平行:0.1758878 非平行:0.0444636
平行:0.1687637 非平行:0.0444338
平行:0.1677679 非平行:0.0445771
平行:0.1191462 非平行:0.0446116
平行:0.1702483 非平行:0.0454863
平行:0.1143605 非平行:0.0451731
平行:0.2155218 非平行:0.0450392
好吧,您可以获得的最佳答案是 运行 分析器工具并衡量您的代码发生了什么。但我有根据的猜测是,您的并行代码速度较慢,因为您的代码非常简单,以至于启动线程和在线程之间切换会增加如此多的成本,以至于计算速度方面的任何优势都可以忽略不计。
但是尝试进行一些实质性的计算,您最终将拥有并行执行的优势。你的代码太简单了。现代 CPU 不会以这种方式加载。
由于我无法将其添加为评论,因此我将对 post 修改后的代码添加另一个答案。 @ixSci 在他的回答中所说的似乎是正确的。我在执行速度非常快的并行代码体中执行了一个微不足道的操作,但是速度慢的原因是大量时间花在了线程之间的上下文切换上?当我将代码更改为休眠一段时间而不是将 int 值增加 1 时,并行代码大约比非并行版本快 4 倍(我的 CPU 中的内核数)。
for (int i = 0; i < 100; i++)
{
ParallelOptions ops = new ParallelOptions();
ops.MaxDegreeOfParallelism = Environment.ProcessorCount;
var partitioner = Partitioner.Create<int>(Enumerable.Range(1, 5000));
var watch = Stopwatch.StartNew();
Parallel.ForEach<int>(partitioner, ops, x => { Thread.Sleep(1); });
watch.Stop();
Console.WriteLine("Parallel: {0}", watch.Elapsed.TotalSeconds);
watch = Stopwatch.StartNew();
foreach (var x in Enumerable.Range(1, 5000))
{
Thread.Sleep(1);
}
watch.Stop();
Console.WriteLine("Non-parallel: {0}\n", watch.Elapsed.TotalSeconds);
}
前 10 个结果:
平行:1.2887589 Non-parallel: 5.0020569
平行:1.277047 Non-parallel: 5.0011116
平行:1.2790631 Non-parallel: 5.0001498
平行:1.2770644 Non-parallel: 5.0052016
平行:1.2770013 Non-parallel: 5.0021479
平行:1.2770031 Non-parallel: 5.0001927
平行:1.2799937 Non-parallel: 5.0062141
平行:1.2819909 Non-parallel: 5.0171945
平行:1.2780496 Non-parallel: 5.0071667
平行:1.2821714 Non-parallel: 5.0082108
平行:1.2777875 Non-parallel: 5.0152099