王朝网络
分享
 
 
 

数组排序LINQ的性能优势初步分析 —— 不起眼的属性

王朝学院·作者佚名  2010-01-27  
宽屏版  字体: |||超大  

话说前阵子姜敏兄对Array.Sort和Enumerable.OrderBy方法进行了一次足够严密的性能测试。可结论似乎与理论和预期不符,但这个结论却是在一个相对严谨的环境下测出,也勾起了各位大牛的兴趣。偶也在偶的机器上测试了一把,当然偶先把一些无关的代码整理了一下:

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Runtime.InteropServices;

using System.Threading;

namespace Exam11

{

public static class CodeTimer

{

public static void Initialize()

{

Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;

Thread.CurrentThread.Priority = ThreadPriority.Highest;

Time( "", 1, () => { } );

}

public static void Time( string name, int iteration, Action action )

{

if ( String.IsNullOrEmpty( name ) ) return;

// warm up

action();

// 1.

ConsoleColor currentForeColor = Console.ForegroundColor;

Console.ForegroundColor = ConsoleColor.Yellow;

Console.WriteLine( name );

// 2.

GC.Collect( GC.MaxGeneration, GCCollectionMode.Forced );

int[] gcCounts = new int[GC.MaxGeneration + 1];

for ( int i = 0; i <= GC.MaxGeneration; i++ )

{

gcCounts[i] = GC.CollectionCount( i );

}

// 3.

Stopwatch watch = new Stopwatch();

watch.Start();

ulong cycleCount = GetCycleCount();

for ( int i = 0; i < iteration; i++ ) action();

ulong cpuCycles = GetCycleCount() - cycleCount;

watch.Stop();

// 4.

Console.ForegroundColor = currentForeColor;

Console.WriteLine( "\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString( "N0" ) + "ms" );

Console.WriteLine( "\tCPU Cycles:\t" + cpuCycles.ToString( "N0" ) );

// 5.

for ( int i = 0; i <= GC.MaxGeneration; i++ )

{

int count = GC.CollectionCount( i ) - gcCounts[i];

Console.WriteLine( "\tGen " + i + ": \t\t" + count );

}

Console.WriteLine();

}

private static ulong GetCycleCount()

{

ulong cycleCount = 0;

QueryThreadCycleTime( GetCurrentThread(), ref cycleCount );

return cycleCount;

}

[DllImport( "kernel32.dll" )]

[return: MarshalAs( UnmanagedType.Bool )]

static extern bool QueryThreadCycleTime( IntPtr threadHandle, ref ulong cycleTime );

[DllImport( "kernel32.dll" )]

static extern IntPtr GetCurrentThread();

}

class Program

{

static void Main( string[] args )

{

var random = new Random( DateTime.Now.Millisecond );

var array = Enumerable.Repeat( 0, 50000 ).Select( _ => new Person { ID = random.Next() } ).ToArray();

//老赵程序

CodeTimer.Initialize();

CodeTimer.Time( "SortWithCustomComparer", 500, () => SortWithCustomComparer( CloneArray( array ) ) );

CodeTimer.Time( "SortWithLinq", 500, () => SortWithLinq( CloneArray( array ) ) );

Console.ReadLine();

}

private static void SortWithCustomComparer( Person[] array )

{

Array.Sort( array, new PersonComparer() );

}

private static void SortWithLinq( Person[] array )

{

var sorted =

( from person in array

orderby person.ID

select person ).ToList();

}

private static T[] CloneArray<T>( T[] source )

{

var dest = new T[source.Length];

Array.Copy( source, dest, source.Length );

return dest;

}

}

public class Person

{

public string FirstName

{

get;

set;

}

public string LastName

{

get;

set;

}

public int ID

{

get;

set;

}

}

public class PersonComparer : IComparer<Person>

{

public int Compare( Person x, Person y )

{

return x.ID - y.ID;

}

}

}

测试的结果的的确确是Enumerable.OrderBy明显可以察觉出来的优势,即使是在Release编译方式下。

从原理上来说,这是不可能的,那么他们一定有什么地方存在某种不公平竞争。

我重新审视了整个代码,调整了两个测试代码的位置:

CodeTimer.Time( "SortWithLinq", 100, () => SortWithLinq( CloneArray( array ) ) );

CodeTimer.Time( "SortWithCustomComparer", 100, () => SortWithCustomComparer( CloneArray( array ) ) );

当然,这不会有任何效果。其次我又发现这个comparer实例被创建了多次(其实也就100次),遂优化如下:

private static PersonComparer comparer = new PersonComparer();

private static void SortWithCustomComparer( Person[] array )

{

Array.Sort( array, comparer );

}

对结果也没有什么改善。

所以我只能将目光集中到comparer的实现上:

public class PersonComparer : IComparer<Person>

{

public int Compare( Person x, Person y )

{

return x.ID - y.ID;

}

}

这并不是一个公平的做法,但应该也不会引起性能问题,将其改成如下形式:

public int Compare( Person x, Person y )

{

return x.ID.CompareTo( y.ID );

}

性能依然没有什么改善,反而还有小幅下降(这也正常)。

似乎陷入了僵局?事实上我们已经非常接近事实的真相了,其实标题都已经将答案公布了。因为问题就出在person.ID是一个属性,这里其实调用了三次方法。

所以只需要简单的将ID改成一个字段,性能结果便与预期的相近了。

那么在这里,LINQ为什么会有优势呢?啊,如果你了解LINQ的排序原理,其实不难想到,LINQ可以节省很多次Person.get_ID的调用。我相信这个分析,会在大牛的下一篇文章详细阐述的,我就不在这里献丑了。

所以结论也可以出来了,但还是令人有点小意外,LINQ在某些环境下的确是有性能优势的,这个理论上是成立的。但我想说的是,其实还有很多因素会影响到这个结论,我们真的不能以偏概全的说,LINQ一定有性能优势或是Array.Sort一定有性能优势。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有