On dit que frère Jiang Min a effectué il y a quelque temps un test de performance suffisamment rigoureux sur les méthodes Array.Sort et Enumerable.OrderBy. La conclusion semble incompatible avec la théorie et les attentes, mais cette conclusion a été mesurée dans un environnement relativement rigoureux, ce qui a également suscité l'intérêt des experts. Je l'ai également testé sur ma machine, bien sûr, j'ai d'abord trié quelques codes non pertinents :
utiliser le système ;
en utilisant System.Collections.Generic ;
en utilisant System.Diagnostics ;
en utilisant System.Linq ;
en utilisant System.Runtime.InteropServices ;
en utilisant System.Threading ;
espace de noms Exam11
{
classe statique publique CodeTimer
{
public static void Initialize()
{
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
Heure( "", 1, () => { } );
}
public static void Time (nom de chaîne, itération int, action action)
{
if ( String.IsNullOrEmpty( name ) ) return;
// réchauffer
action();
// 1.
ConsoleColor currentForeColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine( nom );
// 2.
GC.Collect( GC.MaxGeneration, GCCollectionMode.Forced );
int[] gcCounts = new int[GC.MaxGeneration + 1];
pour ( int i = 0; i <= GC.MaxGeneration; i++ )
{
gcCounts[i] = GC.CollectionCount(i);
}
// 3.
Chronomètre = nouveau Chronomètre();
regarder.Start();
ulong cycleCount = GetCycleCount();
pour ( int i = 0; i < itération; i++ ) action();
ulong cpuCycles = GetCycleCount() - cycleCount;
regarder.Stop();
// 4.
Console.ForegroundColor = currentForeColor ;
Console.WriteLine( "tTime Elapsed:t" + watch.ElapsedMilliseconds.ToString( "N0" ) + "ms" );
Console.WriteLine( "tCPU Cycles:t" + cpuCycles.ToString( "N0" ) );
// 5.
pour ( int i = 0; i <= GC.MaxGeneration; i++ )
{
int count = GC.CollectionCount(i) - gcCounts[i];
Console.WriteLine( "tGen " + i + ": tt" + count );
}
Console.WriteLine();
}
ulong statique privé GetCycleCount()
{
ulong cycleCount = 0 ;
QueryThreadCycleTime( GetCurrentThread(), ref cycleCount );
retourner cycleCount ;
}
[DllImport( "kernel32.dll" )]
[retour : MarshalAs (UnmanagedType.Bool)]
static extern bool QueryThreadCycleTime (IntPtr threadHandle, ref ulong cycleTime);
[DllImport( "kernel32.dll" )]
externe statique IntPtr GetCurrentThread();
}
Programme de classe
{
static void Main( string[] arguments)
{
var random = new Random(DateTime.Now.Millisecond);
var array = Enumerable.Repeat( 0, 50000 ).Select( _ => new Person { ID = random.Next() } ).ToArray();
//Programme Lao Zhao
CodeTimer.Initialize();
CodeTimer.Time( "SortWithCustomComparer", 500, () => SortWithCustomComparer( CloneArray( array ) ) );
CodeTimer.Time( "SortWithLinq", 500, () => SortWithLinq( CloneArray( array ) ) );
Console.ReadLine();
}
vide statique privé SortWithCustomComparer (Tableau Person[])
{
Array.Sort( tableau, new PersonComparer() );
}
vide statique privé SortWithLinq( Tableau Person[] )
{
var trié =
(de la personne dans le tableau
commande par personne.ID
sélectionnez la personne .ToList();
}
privé statique T[] CloneArray<T>( T[] source)
{
var dest = nouveau T[source.Longueur];
Array.Copy( source, destination, source.Length );
retourner la destination ;
}
}
Personne de classe publique
{
chaîne publique Prénom
{
obtenir;
ensemble;
}
chaîne publique Nom de famille
{
obtenir;
ensemble;
}
identifiant international public
{
obtenir;
ensemble;
}
}
classe publique PersonComparer : IComparer<Person>
{
public int Comparer (Personne x, Personne y)
{
retourner x.ID - y.ID ;
}
}
}
Les résultats des tests montrent en effet les avantages évidents d'Enumerable.OrderBy, même en mode compilation Release.
En principe, cela est impossible et il doit donc y avoir une concurrence déloyale quelque part.
J'ai revisité l'intégralité du code et ajusté la position des deux codes de test :
CodeTimer.Time( "SortWithLinq", 100, () => SortWithLinq( CloneArray( array ) ) );
CodeTimer.Time( "SortWithCustomComparer", 100, () => SortWithCustomComparer( CloneArray( array ) ) );
Bien entendu, cela n’aura aucun effet. Deuxièmement, j'ai constaté que cette instance de comparateur avait été créée plusieurs fois (en fait seulement 100 fois), je l'ai donc optimisée comme suit :
comparateur PersonComparer statique privé = new PersonComparer();
vide statique privé SortWithCustomComparer (Tableau Person[])
{
Array.Sort(tableau, comparer);
}
Il n'y a aucune amélioration dans les résultats.
Je ne peux donc me concentrer que sur l'implémentation du comparateur :
classe publique PersonComparer : IComparer<Person>
{
public int Comparer (Personne x, Personne y)
{
retourner x.ID - y.ID ;
}
}
Il ne s'agit pas d'une approche équitable, mais elle ne devrait pas entraîner de problèmes de performances. Modifiez-la sous la forme suivante :
public int Comparer (Personne x, Personne y)
{
retourner x.ID.CompareTo( y.ID );
}
Il n’y a toujours pas d’amélioration des performances, mais une légère diminution (c’est normal).
On dirait que nous sommes dans une impasse ? En fait, nous sommes très proches de la vérité. En fait, le titre a déjà annoncé la réponse. Parce que le problème réside dans le fait que person.ID est un attribut, la méthode est en fait appelée trois fois ici.
Il suffit donc de remplacer l'ID par un champ et les résultats en termes de performances seront proches de ceux attendus.
Alors pourquoi LINQ a-t-il un avantage ici ? Ah, si vous comprenez le principe de tri de LINQ, il n'est pas difficile de penser que LINQ peut enregistrer de nombreux appels à Person.get_ID. Je pense que cette analyse sera développée dans le prochain article de Daniel, je ne vais donc pas la montrer ici.
La conclusion peut donc être tirée, mais elle reste un peu surprenante. LINQ présente des avantages en termes de performances dans certains environnements. Cette théorie est établie. Mais ce que je veux dire, c'est qu'il existe en fait de nombreux facteurs qui affecteront cette conclusion. Nous ne pouvons vraiment pas dire de manière générale que LINQ doit avoir des avantages en termes de performances ou qu'Array.Sort doit avoir des avantages en termes de performances.