今天很热闹啊。老赵的数组排序方法的性能比较(中):Array.Sort<T>实现分析Ivony的 数组排序LINQ的性能优势初步分析 —— 不起眼的属性等有关linq性能文章让我忍不住写下此文章。

      Ivony的提供的代码中,对数组的排序时采用自定义的PersonComparer,而linq排序使用的确是Comparer<int>.Default,代码分析如下:

      数组排序     

private static void SortWithCustomComparer(Person[] array)
 {
    Array.Sort(array, 
new PersonComparer());
}

    LINQ排序    

private static void SortWithLinq( Person[] array )
{
    var sorted 
=
        ( from person 
in array
         orderby person.ID
         select person ).ToList();
}

     上述lambda表达式对应为varsorted = Enumerable.OrderBy<Person,int>(array,person =>person.ID).ToList()。通过reflector反汇编可以得到以下代码

代码
//Enumerable类中OrderBy的代码
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    
return new OrderedEnumerable<TSource, TKey>(source, keySelector, nullfalse);
}

//内部类OrderedEnumerable的代码
internal class OrderedEnumerable<TElement, TKey> : OrderedEnumerable<TElement>
{
    
// Fields
    internal IComparer<TKey> comparer;
    
internal bool descending;
    
internal Func<TElement, TKey> keySelector;
    
internal OrderedEnumerable<TElement> parent;

    
// Methods
    internal OrderedEnumerable(IEnumerable<TElement> source, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
    {
        
if (source == null)
        {
            
throw Error.ArgumentNull("source");
        }
        
if (keySelector == null)
        {
            
throw Error.ArgumentNull("keySelector");
        }
        
base.source = source;
        
this.parent = null;
        
this.keySelector = keySelector;
        
this.comparer = (comparer != null? comparer : ((IComparer<TKey>) Comparer<TKey>.Default);
        
this.descending = descending;
    }

    
internal override EnumerableSorter<TElement> GetEnumerableSorter(EnumerableSorter<TElement> next)
    {
        EnumerableSorter
<TElement> enumerableSorter = new EnumerableSorter<TElement, TKey>(this.keySelector, this.comparer, this.descending, next);
        
if (this.parent != null)
        {
            enumerableSorter 
= this.parent.GetEnumerableSorter(enumerableSorter);
        }
        
return enumerableSorter;
    }
}

 

      在文章数组排序方法的性能比较(上):注意事项及试验,老赵测试得出的结果可以得知PersonComparer比Comparer<int>.Default排序慢。

      在增加一个新的SortWithLinq2方法之后,release运行测试,我得到新的结果。

      新代码: 

代码
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(050000).Select(_ => new Person { ID = random.Next() }).ToArray();

            JetBrains.dotTrace.Api.CPUProfiler.Start();

            
//老赵程序
            CodeTimer.Initialize();
            CodeTimer.Time(
"SortWithCustomComparer"500, () => SortWithCustomComparer(CloneArray(array)));
            CodeTimer.Time(
"SortWithLinq2"500, () => SortWithLinq(CloneArray(array)));
            CodeTimer.Time(
"SortWithLinq"500, () => SortWithLinq2(CloneArray(array)));

            JetBrains.dotTrace.Api.CPUProfiler.StopAndSaveSnapShot();                   
        }

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

            Console.WriteLine(name);

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

        
private static readonly PersonComparer comparer = new PersonComparer();

        
private static void SortWithCustomComparer(Person[] array)
        {
            Array.Sort(array, comparer);
        }

        
private static void SortWithLinq(Person[] array)
        {
            
//array = (from person in array
            
//         orderby person.ID
            
//         select person).ToList();
             Enumerable.OrderBy<Person,int>(array,person =>person.ID).ToList();
        }

        
private static void SortWithLinq2(Person[] array)
        {
            
//array = (from person in array
            
//         orderby person.ID
            
//         select person).ToList();
            Enumerable.OrderBy<Person, Person>(array, person => person, comparer).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 override int GetHashCode()
        {
            
return this.ID.GetHashCode();
        }
    }

    
public class PersonComparer : IComparer<Person>
    {
        
public int Compare(Person x, Person y)
        {
            
return x.ID - y.ID;
        }

    }
}

 

 

    不使用dottrace探测得到测试结果(使用dottrace之后运行态慢了,而且不好得到控制台的显示结果,除非使用辅助软件):

SortWithCustomComparer
        Time Elapsed:   11,446ms
        CPU Cycles:     26,201,674,700
        Gen 0:          31
        Gen 1:          31
        Gen 2:          31

SortWithLinq
        Time Elapsed:   14,970ms
        CPU Cycles:     34,259,890,929
        Gen 0:          311
        Gen 1:          310
        Gen 2:          187

SortWithLinq2
        Time Elapsed:   18,573ms
        CPU Cycles:     42,491,287,773
        Gen 0:          311
        Gen 1:          311
        Gen 2:          187 

       使用dottrace的分析图如如下(启动dottrace后程序运行的时间比之前的慢多了):

 

      上述结果测试表明,在使用PersonComparer之后SortWithLinq2比SortWithLinq慢了差不多一倍。在此也印证老赵的相关分析。

 

 

posted on 2010-01-22 17:02  分享 共赢  阅读(2246)  评论(7编辑  收藏  举报