.net 4.0 对于这段代码,为什么PLINQ比LINQ慢?
首先,我在一台双核2.66Ghz处理器机器上运行它。我不确定.AsParallel()调用是否在正确的位置。我也直接在范围变量上进行了尝试,但速度仍然较慢。我不明白为什么 以下是我的结果: 进程非并行1000花费了146毫秒.net 4.0 对于这段代码,为什么PLINQ比LINQ慢?,.net-4.0,parallel-processing,plinq,.net 4.0,Parallel Processing,Plinq,首先,我在一台双核2.66Ghz处理器机器上运行它。我不确定.AsParallel()调用是否在正确的位置。我也直接在范围变量上进行了尝试,但速度仍然较慢。我不明白为什么 以下是我的结果: 进程非并行1000花费了146毫秒 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace DemoConsoleApp { internal class
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace DemoConsoleApp
{
internal class Program
{
private static void Main()
{
ReportOnTimedProcess(
() => GetIntegerCombinations(),
"non-parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(runAsParallel: true),
"parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000),
"non-parallel 5000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000, true),
"parallel 5000");
Console.Read();
}
private static List<Tuple<int, int>> GetIntegerCombinations(
int iterationCount = 1000, bool runAsParallel = false)
{
IEnumerable<int> range = Enumerable.Range(1, iterationCount);
IEnumerable<Tuple<int, int>> integerCombinations =
from x in range
from y in range
select new Tuple<int, int>(x, y);
return runAsParallel
? integerCombinations.AsParallel().ToList()
: integerCombinations.ToList();
}
private static void ReportOnTimedProcess(
Action process, string processName)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
process();
stopwatch.Stop();
Console.WriteLine("Process {0} took {1} milliseconds",
processName, stopwatch.ElapsedMilliseconds);
}
}
}
进程并行1000花费了156毫秒
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace DemoConsoleApp
{
internal class Program
{
private static void Main()
{
ReportOnTimedProcess(
() => GetIntegerCombinations(),
"non-parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(runAsParallel: true),
"parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000),
"non-parallel 5000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000, true),
"parallel 5000");
Console.Read();
}
private static List<Tuple<int, int>> GetIntegerCombinations(
int iterationCount = 1000, bool runAsParallel = false)
{
IEnumerable<int> range = Enumerable.Range(1, iterationCount);
IEnumerable<Tuple<int, int>> integerCombinations =
from x in range
from y in range
select new Tuple<int, int>(x, y);
return runAsParallel
? integerCombinations.AsParallel().ToList()
: integerCombinations.ToList();
}
private static void ReportOnTimedProcess(
Action process, string processName)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
process();
stopwatch.Stop();
Console.WriteLine("Process {0} took {1} milliseconds",
processName, stopwatch.ElapsedMilliseconds);
}
}
}
进程非并行5000花费了5187毫秒
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace DemoConsoleApp
{
internal class Program
{
private static void Main()
{
ReportOnTimedProcess(
() => GetIntegerCombinations(),
"non-parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(runAsParallel: true),
"parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000),
"non-parallel 5000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000, true),
"parallel 5000");
Console.Read();
}
private static List<Tuple<int, int>> GetIntegerCombinations(
int iterationCount = 1000, bool runAsParallel = false)
{
IEnumerable<int> range = Enumerable.Range(1, iterationCount);
IEnumerable<Tuple<int, int>> integerCombinations =
from x in range
from y in range
select new Tuple<int, int>(x, y);
return runAsParallel
? integerCombinations.AsParallel().ToList()
: integerCombinations.ToList();
}
private static void ReportOnTimedProcess(
Action process, string processName)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
process();
stopwatch.Stop();
Console.WriteLine("Process {0} took {1} milliseconds",
processName, stopwatch.ElapsedMilliseconds);
}
}
}
进程并行5000花费了5300毫秒
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace DemoConsoleApp
{
internal class Program
{
private static void Main()
{
ReportOnTimedProcess(
() => GetIntegerCombinations(),
"non-parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(runAsParallel: true),
"parallel 1000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000),
"non-parallel 5000");
ReportOnTimedProcess(
() => GetIntegerCombinations(5000, true),
"parallel 5000");
Console.Read();
}
private static List<Tuple<int, int>> GetIntegerCombinations(
int iterationCount = 1000, bool runAsParallel = false)
{
IEnumerable<int> range = Enumerable.Range(1, iterationCount);
IEnumerable<Tuple<int, int>> integerCombinations =
from x in range
from y in range
select new Tuple<int, int>(x, y);
return runAsParallel
? integerCombinations.AsParallel().ToList()
: integerCombinations.ToList();
}
private static void ReportOnTimedProcess(
Action process, string processName)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
process();
stopwatch.Stop();
Console.WriteLine("Process {0} took {1} milliseconds",
processName, stopwatch.ElapsedMilliseconds);
}
}
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
名称空间DemoConsoleApp
{
内部课程计划
{
私有静态void Main()
{
ReportOnTimedProcess(
()=>GetIntegerCombinations(),
“非平行1000”);
ReportOnTimedProcess(
()=>GetIntegerCombinations(runAsParallel:true),
“平行1000”);
ReportOnTimedProcess(
()=>GetIntegerCombinations(5000),
“非平行5000”);
ReportOnTimedProcess(
()=>GetIntegerCombinations(5000,true),
“平行5000”);
Console.Read();
}
私有静态列表GetIntegerCombinations(
int iterationCount=1000,bool runAsParallel=false)
{
IEnumerable range=Enumerable.range(1,迭代计数);
IEnumerable整数组合=
从范围内的x开始
在范围内从y开始
选择新元组(x,y);
返回运行通道
?integerCombinations.AsParallel().ToList()
:integerCombinations.ToList();
}
私有静态void ReportOnTimedProcess(
操作进程,字符串(进程名称)
{
var stopwatch=新秒表();
秒表。开始();
过程();
秒表;
WriteLine(“进程{0}花费了{1}毫秒”,
进程名称,秒表。ElapsedMilliseconds);
}
}
}
它稍微慢一点,因为PLINQ有一定的开销(线程、调度等),所以您必须仔细选择要并行化的内容。您正在进行基准测试的特定代码实际上不值得并行化,您必须对负载较大的任务进行并行化,否则开销将超过并行化的好处。您在这里的大部分执行时间可能是通过ToList()实际创建列表
方法。这将需要执行几次内存分配、调整列表大小等等。在这里,并行化也没有带来太多好处,因为最后的操作必须同步(在输出上构建一个列表)
试着在并行段中做一些更复杂/更昂贵的事情,比如素数分解,并将迭代次数增加到数十万次(在分析时使用5000是一个非常小的数字)。那么你应该开始看到区别了
还要确保在发布模式下进行评测;我经常看到尝试在调试模式下进行评测,结果并不准确。当迭代计数设置为5000(5000*5000)时,我的示例中的代码实际上会创建2500万个元组组合。我想我看到的问题是,每个逻辑迭代太小,无法并行。谢谢