姜敏兄弟は少し前に Array.Sort メソッドと Enumerable.OrderBy メソッドに関して十分に厳密なパフォーマンス テストを実施したと言われています。この結論は理論や期待と矛盾しているように見えますが、この結論は比較的厳格な環境で測定されたものであり、専門家の関心も呼び起こしました。もちろん、最初に無関係なコードをいくつか整理しました。
システムを使用する;
System.Collections.Generic を使用します。
System.Diagnostics を使用します。
System.Linq を使用します。
System.Runtime.InteropServices を使用します。
System.Threading を使用します。
名前空間 Exam11
{
パブリック静的クラス CodeTimer
{
public static void Initialize()
{
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Time( "", 1, () => { } );
}
public static void Time(文字列名、反復、アクションaction)
{
if ( String.IsNullOrEmpty( name ) ) return;
// 準備し始める
アクション();
// 1.
ConsoleColor currentForeColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine( 名前 );
// 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.
ストップウォッチ watch = new Stopwatch();
watch.Start();
ulong サイクルカウント = GetCycleCount();
for ( int i = 0; i < iteration; i++ ) action();
ulong cpuCycles = GetCycleCount() - サイクルカウント;
watch.Stop();
// 4.
Console.ForegroundColor = currentForeColor;
Console.WriteLine( "t経過時間:t" + watch.ElapsedMilliseconds.ToString( "N0" ) + "ms" );
Console.WriteLine( "tCPU サイクル:t" + cpuCycles.ToString( "N0" ) );
// 5.
for ( int i = 0; i <= GC.MaxGeneration; i++ )
{
int カウント = GC.CollectionCount(i) - gcCounts[i];
Console.WriteLine( "tGen " + i + ": tt" + count );
}
Console.WriteLine();
}
プライベート静的 ulong GetCycleCount()
{
ulong サイクルカウント = 0;
QueryThreadCycleTime( GetCurrentThread(), refcycleCount );
サイクルカウントを返します。
}
[DllImport( "kernel32.dll" )]
[戻り値: MarshalAs(UnmanagedType.Bool)]
static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulongcycleTime);
[DllImport( "kernel32.dll" )]
静的 extern IntPtr GetCurrentThread();
}
クラスプログラム
{
static void Main( string[] args )
{
var ランダム = 新しいランダム(DateTime.Now.ミリ秒);
var array = Enumerable.Repeat( 0, 50000 ).Select( _ => 新しい人 { 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( 配列, new PersonComparer() );
}
private static void SortWithLinq( Person[] array )
{
ソートされた変数 =
(配列の人から
注文者ID別
人を選択 ).ToList();
}
プライベート静的 T[] CloneArray<T>( T[] ソース )
{
var dest = 新しい T[source.Length];
Array.Copy( ソース、宛先、ソース.長さ );
戻り先;
}
}
パブリッククラスの人
{
パブリック文字列名
{
得る;
セット;
}
パブリック文字列姓
{
得る;
セット;
}
パブリック整数ID
{
得る;
セット;
}
}
パブリック クラス PersonComparer : IComparer<person>
{
public int Compare( 人 x , 人 y )
{
x.ID - y.ID を返します。
}
}
}
テスト結果は、リリース コンパイル モードであっても、Enumerable.OrderBy の明白な利点を実際に示しています。
原理的にそんなことはあり得ないので、どこかで不当な競争が行われているはずです。
コード全体を再検討し、2 つのテスト コードの位置を調整しました。
CodeTimer.Time( "SortWithLinq", 100, () => SortWithLinq( CloneArray( array ) ) );
CodeTimer.Time( "SortWithCustomComparer", 100, () => SortWithCustomComparer( CloneArray( array ) ) );
もちろん、これでは何の効果もありません。次に、この比較子インスタンスが複数回 (実際には 100 回だけ) 作成されたことがわかったので、次のように最適化しました。
プライベート静的 PersonComparer 比較子 = new PersonComparer();
private static void SortWithCustomComparer( Person[] array )
{
Array.Sort(配列, 比較子);
}
結果に改善はありません。
したがって、私は比較子の実装にのみ焦点を当てることができます。
パブリック クラス PersonComparer : IComparer<person>
{
public int Compare( 人 x, 人 y )
{
x.ID - y.ID を返します。
}
}
これは公平なアプローチではありませんが、パフォーマンスの問題が発生することはありません。次の形式に変更してください。
public int Compare( 人 x, 人 y )
{
return x.ID.CompareTo( y.ID );
}
パフォーマンスの向上はまだありませんが、わずかに低下しています (これは正常です)。
行き詰まりのようですか?実は、その答えはタイトルですでに発表されています。問題は person.ID が属性であることにあるため、ここではメソッドが実際に 3 回呼び出されます。
したがって、ID をフィールドに変更するだけで、パフォーマンスの結果は期待に近いものになります。
では、なぜ LINQ がここで有利なのでしょうか?ああ、LINQ の並べ替え原理を理解していれば、LINQ によって Person.get_ID への多くの呼び出しを節約できると考えるのは難しくありません。この分析はダニエルの次の記事で詳しく説明されると思いますので、ここでは紹介しません。
したがって、結論は得られますが、それでも、特定の環境では LINQ にパフォーマンス上の利点があるという理論が確立されています。しかし、私が言いたいのは、実際には、この結論に影響を与える要因がたくさんあるということです。LINQ にはパフォーマンス上の利点がある、または Array.Sort にはパフォーマンス上の利点がある、とは一概に言えません。