性能Linq

时间:2012-08-24 07:18:45

标签: .net performance linq plinq parallel.foreach

今天我测试了Linq和PLinq查询的性能影响。 因此我使用了msdn How to: Measure PLINQ Query Performance上的文章。

void Main()
{
        var source = Enumerable.Range(0, 600000000);
        System.Diagnostics.Stopwatch sw;    

        var queryToMeasure1 = from num in source
                             where num % 3 == 0
                             select Math.Sqrt(num);

        var queryToMeasure2 = from num in source.AsParallel()
                             where num % 3 == 0
                             select Math.Sqrt(num);                          

        long freq = Stopwatch.Frequency;
        Console.WriteLine("Timer frequency in ticks per second = {0}", freq);

        Console.WriteLine("Measuring 1");
        sw = System.Diagnostics.Stopwatch.StartNew();   
        foreach (var n in queryToMeasure1) { }  
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);      

        Console.WriteLine("Measuring 2");
        sw = System.Diagnostics.Stopwatch.StartNew();   
        foreach (var n in queryToMeasure2) { }  
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);

        Console.WriteLine("Measuring 3");
        sw = System.Diagnostics.Stopwatch.StartNew();           
        System.Threading.Tasks.Parallel.ForEach(queryToMeasure1, n => {});          
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);

        Console.WriteLine("Measuring 4");
        sw = System.Diagnostics.Stopwatch.StartNew();           
        System.Threading.Tasks.Parallel.ForEach(queryToMeasure2, n => {});      
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds);

        Console.WriteLine("Measuring 5");
        sw = System.Diagnostics.Stopwatch.StartNew();   
        queryToMeasure2.ForAll(n => {});    
        Console.WriteLine("Total ticks: {0} - Elapsed time: {1} ms", sw.ElapsedTicks, sw.ElapsedMilliseconds););
}

测试环境:Win7 Enterprise上的LinqPad4,64位,8GB内存,I7-2600(8位)

我想出了,并且无法解释为什么一个核心(测量1)上的查询比并行查询更快。我是否必须添加更多选择代表才能从并行任务中受益?

但现在的结果是:

1.Run:可数范围为60000:

Timer frequency in ticks per second = 3312851
Measuring 1
Total ticks: 3525 - Elapsed time: 1 ms
Measuring 2
Total ticks: 15802 - Elapsed time: 4 ms
Measuring 3
Total ticks: 5940 - Elapsed time: 1 ms
Measuring 4
Total ticks: 26862 - Elapsed time: 8 ms
Measuring 5
Total ticks: 4387 - Elapsed time: 1 ms

2.Run:可枚举的范围为600000000:

Timer frequency in ticks per second = 3312851
Measuring 1
Total ticks: 29740243 - Elapsed time: 8977 ms
Measuring 2
Total ticks: 33722438 - Elapsed time: 10179 ms
Measuring 3
Total ticks: 77145502 - Elapsed time: 23286 ms
Measuring 4
Total ticks: 120078284 - Elapsed time: 36246 ms
Measuring 5
Total ticks: 30899585 - Elapsed time: 9327 ms

有趣的事实:在执行测试脚本之前使用垃圾收集器会大大增加测量4的时间:

3.Run:可枚举的600000000范围和垃圾收集器(来自LinqPad):

Timer frequency in ticks per second = 3312851
Measuring 1
Total ticks: 29597830 - Elapsed time: 8934 ms
Measuring 2
Total ticks: 33532083 - Elapsed time: 10121 ms
Measuring 3
Total ticks: 76403692 - Elapsed time: 23062 ms
Measuring 4
Total ticks: 58534548 - Elapsed time: 17668 ms
Measuring 5
Total ticks: 32943622 - Elapsed time: 9944 ms

总之,我可以说当选择代表增加时,方法1是执行小选择查询和方法5的最合适选项吗?

1 个答案:

答案 0 :(得分:1)

你的计算非常便宜。它们甚至不是非并行LINQ的良好候选者,因为委托调用可能比计算本身更昂贵。 PLINQ有许多额外的开销,如启动任务,跨线程同步和复制数据。试试这个:

bool Where(int i) {
 var sum = 0; 
 for (10000 times) {
  sum += i;
 }
 return i % 3 == 0;
}

在where子句中使用该函数。此功能非常昂贵,因此线程和同步所产生的开销将不再占据运行时间。

基本上,您正在测量PLINQ的最坏情况用例。尝试测量一个有趣的。