Performance des tableaux vs listes

Disons que vous devez avoir une liste / un tableau d’entiers que vous devez itérer fréquemment, et je veux dire très souvent. Les raisons peuvent varier, mais disent que c’est au cœur de la boucle la plus interne d’un traitement à haut volume.

En général, on opterait pour l’utilisation des listes (liste) en raison de leur flexibilité en taille. En plus de cela, la documentation de msdn affirme que les listes utilisent un tableau en interne et doivent être aussi rapides (un rapide coup d’œil avec Reflector le confirme). Inévitablement, des frais généraux sont impliqués.

Est-ce que quelqu’un a réellement mesuré cela? Est-ce qu’itérer 6M fois à travers une liste prendrait le même temps qu’un tableau?

Très facile à mesurer …

Dans un petit nombre de code de traitement en boucle serrée où je sais que la longueur est fixe, j’utilise des baies pour ce tout petit peu de micro-optimisation; les tableaux peuvent être légèrement plus rapides si vous utilisez l’indexeur / for form – mais l’IIRRC pense que cela dépend du type de données du tableau. Mais à moins que vous ayez besoin de micro-optimiser, gardez-le simple et utilisez List etc.

Bien sûr, cela ne s’applique que si vous lisez toutes les données. un dictionnaire serait plus rapide pour les recherches basées sur des clés.

Voici mes résultats en utilisant “int” (le deuxième nombre est une sum de contrôle pour vérifier qu’ils ont tous fait le même travail):

(édité pour corriger le bug)

 List/for: 1971ms (589725196) Array/for: 1864ms (589725196) List/foreach: 3054ms (589725196) Array/foreach: 1860ms (589725196) 

basé sur le banc d’essai:

 using System; using System.Collections.Generic; using System.Diagnostics; static class Program { static void Main() { List list = new List(6000000); Random rand = new Random(12345); for (int i = 0; i < 6000000; i++) { list.Add(rand.Next(5000)); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.ReadLine(); } } 

Réponse courte:

sens de la couleur

Tableau vs liste vs liste liée

Réponse plus détaillée, vous trouverez le lien suivant: https://stackoverflow.com/a/29263914/4423545

Je pense que la performance sera assez similaire. La surcharge impliquée lors de l’utilisation d’une liste par rapport à un tableau est IMHO lorsque vous ajoutez des éléments à la liste et que la liste doit augmenter la taille du tableau qu’elle utilise en interne lorsque la capacité du tableau est atteinte.

Supposons que vous ayez une liste d’une capacité de 10, alors la liste augmentera sa capacité une fois que vous voulez append le onzième élément. Vous pouvez réduire l’impact des performances en initialisant la capacité de la liste sur le nombre d’éléments qu’elle contiendra.

Mais, pour savoir si une itération sur une liste est aussi rapide qu’une itération sur un tableau, pourquoi ne pas la comparer?

 int numberOfElements = 6000000; List theList = new List (numberOfElements); int[] theArray = new int[numberOfElements]; for( int i = 0; i < numberOfElements; i++ ) { theList.Add (i); theArray[i] = i; } Stopwatch chrono = new Stopwatch (); chrono.Start (); int j; for( int i = 0; i < numberOfElements; i++ ) { j = theList[i]; } chrono.Stop (); Console.WriteLine (String.Format("iterating the List took {0} msec", chrono.ElapsedMilliseconds)); chrono.Reset(); chrono.Start(); for( int i = 0; i < numberOfElements; i++ ) { j = theArray[i]; } chrono.Stop (); Console.WriteLine (String.Format("iterating the array took {0} msec", chrono.ElapsedMilliseconds)); Console.ReadLine(); 

Sur mon système itération sur le tableau a pris 33msec; itération sur la liste a pris 66msec.

Pour être honnête, je ne m'attendais pas à ce que la variation soit si grande. J'ai donc mis mon itération en boucle: maintenant, j'exécute les deux itérations 1000 fois. Les résultats sont les suivants:

itération de la liste a pris 67146 msec itération du tableau a pris 40821 msec

Maintenant, la variation n'est plus si grande, mais quand même ...

Par conséquent, j'ai démarré .NET Reflector et le getter de l'indexeur de la classe List ressemble à ceci:

 public T get_Item(int index) { if (index >= this._size) { ThrowHelper.ThrowArgumentOutOfRangeException(); } return this._items[index]; } 

Comme vous pouvez le voir, lorsque vous utilisez l'indexeur de la liste, la liste vérifie si vous ne sortez pas des limites du tableau interne. Ce contrôle supplémentaire a un coût.

Si vous obtenez une valeur unique (et non une boucle), les deux vérifient les limites (vous vous souvenez du code managé), la liste le fait deux fois. Voir les notes plus tard pour savoir pourquoi ce n’est probablement pas une grosse affaire.

Si vous utilisez le vôtre pour (int int i = 0; i

  • Tableau:
    • la vérification des bornes est supprimée
  • Des listes
    • la vérification des bornes est effectuée

Si vous utilisez foreach, la principale différence est la suivante:

  • Tableau:
    • aucun object n’est alloué pour gérer l’itération
    • la vérification des bornes est supprimée
  • Liste via une variable connue sous le nom de List.
    • la variable de gestion des itérations est une stack allouée
    • la vérification des bornes est effectuée
  • Liste via une variable connue pour être IList.
    • la variable de gestion des itérations est un tas alloué
    • La vérification des limites est également effectuée. Les valeurs des listes peuvent ne pas être modifiées pendant la durée alors que celles du tableau peuvent l’être.

La vérification des limites n’est souvent pas une grosse affaire (surtout si vous êtes sur un processeur avec une prédiction de pipeline et de twig approfondie – la norme pour la plupart de nos jours), mais seul votre propre profilage peut vous indiquer si cela pose problème. Si vous êtes dans des parties de votre code où vous évitez les allocations de tas (de bons exemples sont les bibliothèques ou les implémentations de hashcode), vous devez vous assurer que la variable est typée List non IList pour éviter cet écueil. Comme toujours profil si cela compte.

[ Voir aussi cette question ]

J’ai modifié la réponse de Marc pour utiliser des nombres aléatoires réels et faire le même travail dans tous les cas.

Résultats:

          pour foreach
 Tableau: 1575ms 1575ms (+ 0%)
 Liste: 1630ms 2627ms (+ 61%)
          (+ 3%) (+ 67%)

 (Somme de contrôle: -1000038876)

Compilé en version sous VS 2008 SP1. Exécution sans débogage sur un Q6600@2.40GHz, .NET 3.5 SP1.

Code:

 class Program { static void Main(ssortingng[] args) { List list = new List(6000000); Random rand = new Random(1); for (int i = 0; i < 6000000; i++) { list.Add(rand.Next()); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = arr.Length; for (int i = 0; i < len; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.WriteLine(); Console.ReadLine(); } } 

Les mesures sont agréables, mais vous obtiendrez des résultats très différents selon ce que vous faites exactement dans votre boucle interne. Mesurez votre propre situation. Si vous utilisez le multi-threading, cela seul est une activité non sortingviale.

En effet, si vous effectuez des calculs complexes à l’intérieur de la boucle, les performances de l’indexeur de tableaux par rapport à l’indexeur de listes peuvent être si faibles que cela n’a finalement plus d’importance.

N’essayez pas d’append de la capacité en augmentant le nombre d’éléments.

Performance

 List For Add: 1ms Array For Add: 2397ms 

  Stopwatch watch; #region --> List For Add < -- List intList = new List(); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 60000; rpt++) { intList.Add(rand.Next()); } watch.Stop(); Console.WriteLine("List For Add: {0}ms", watch.ElapsedMilliseconds); #endregion #region --> Array For Add < -- int[] intArray = new int[0]; watch = Stopwatch.StartNew(); int sira = 0; for (int rpt = 0; rpt < 60000; rpt++) { sira += 1; Array.Resize(ref intArray, intArray.Length + 1); intArray[rpt] = rand.Next(); } watch.Stop(); Console.WriteLine("Array For Add: {0}ms", watch.ElapsedMilliseconds); #endregion 

En voici un qui utilise les dictionnaires, IEnumerable:

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; static class Program { static void Main() { List list = new List(6000000); for (int i = 0; i < 6000000; i++) { list.Add(i); } Console.WriteLine("Count: {0}", list.Count); int[] arr = list.ToArray(); IEnumerable Ienumerable = list.ToArray(); Dictionary dict = list.ToDictionary(x => x, y => true); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in Ienumerable) { chk += i; } } Console.WriteLine("Ienumerable/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += i; } } Console.WriteLine("Dict/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in Ienumerable) { chk += i; } } watch.Stop(); Console.WriteLine("Ienumerable/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += i; } } watch.Stop(); Console.WriteLine("Dict/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk); Console.ReadLine(); } } 

Comme List <> utilise des tableaux en interne, les performances de base doivent être identiques. Deux raisons pour lesquelles la liste pourrait être légèrement plus lente:

  • Pour rechercher un élément dans la liste, une méthode de List est appelée, qui effectue la recherche dans le tableau sous-jacent. Vous avez donc besoin d’un appel de méthode supplémentaire. D’autre part, le compilateur pourrait le reconnaître et optimiser l’appel “inutile”.
  • Le compilateur peut effectuer des optimisations spéciales s’il connaît la taille du tableau, ce qu’il ne peut pas faire pour une liste de longueur inconnue. Cela peut apporter une amélioration des performances si vous ne disposez que de quelques éléments dans votre liste.

Pour vérifier si cela fait une différence pour vous, il est probablement préférable d’ajuster les fonctions de chronométrage affichées à une liste de la taille que vous prévoyez d’utiliser et de voir comment sont les résultats pour votre cas particulier.

Je craignais que les Benchmarks affichés dans d’autres réponses ne laissent encore au compilateur le soin d’optimiser, d’éliminer ou de fusionner les boucles, et j’en ai écrit une qui:

  • Entrées imprévisibles utilisées (aléatoires)
  • Exécute un calculé avec le résultat imprimé sur la console
  • Modifie les données d’entrée à chaque répétition

Le résultat étant qu’un tableau direct a des performances d’environ 250% supérieures à celles d’un access à un tableau enveloppé dans un IList:

  • 1 milliard d’access au tableau: 4000 ms
  • 1 milliard d’access à la liste: 10000 ms
  • 100 millions d’access au tableau: 350 ms
  • 100 millions d’access à la liste: 1000 ms

Voici le code:

 static void Main(ssortingng[] args) { const int TestPointCount = 1000000; const int RepetitionCount = 1000; Stopwatch arrayTimer = new Stopwatch(); Stopwatch listTimer = new Stopwatch(); Point2[] points = new Point2[TestPointCount]; var random = new Random(); for (int index = 0; index < TestPointCount; ++index) { points[index].X = random.NextDouble(); points[index].Y = random.NextDouble(); } for (int repetition = 0; repetition <= RepetitionCount; ++repetition) { if (repetition > 0) { // first repetition is for cache warmup arrayTimer.Start(); } doWorkOnArray(points); if (repetition > 0) { // first repetition is for cache warmup arrayTimer.Stop(); } if (repetition > 0) { // first repetition is for cache warmup listTimer.Start(); } doWorkOnList(points); if (repetition > 0) { // first repetition is for cache warmup listTimer.Stop(); } } Console.WriteLine("Ignore this: " + points[0].X + points[0].Y); Console.WriteLine( ssortingng.Format( "{0} accesses on array took {1} ms", RepetitionCount * TestPointCount, arrayTimer.ElapsedMilliseconds ) ); Console.WriteLine( ssortingng.Format( "{0} accesses on list took {1} ms", RepetitionCount * TestPointCount, listTimer.ElapsedMilliseconds ) ); } private static void doWorkOnArray(Point2[] points) { var random = new Random(); int pointCount = points.Length; Point2 accumulated = Point2.Zero; for (int index = 0; index < pointCount; ++index) { accumulated.X += points[index].X; accumulated.Y += points[index].Y; } accumulated /= pointCount; // make use of the result somewhere so the optimizer can't eliminate the loop // also modify the input collection so the optimizer can merge the repetition loop points[random.Next(0, pointCount)] = accumulated; } private static void doWorkOnList(IList points) { var random = new Random(); int pointCount = points.Count; Point2 accumulated = Point2.Zero; for (int index = 0; index < pointCount; ++index) { accumulated.X += points[index].X; accumulated.Y += points[index].Y; } accumulated /= pointCount; // make use of the result somewhere so the optimizer can't eliminate the loop // also modify the input collection so the optimizer can merge the repetition loop points[random.Next(0, pointCount)] = accumulated; } 

Comme j’avais une question similaire, cela m’a permis de démarrer rapidement.

Ma question est un peu plus précise: “Quelle est la méthode la plus rapide pour une implémentation de tableau réflexif”

Les tests effectués par Marc Gravell montrent beaucoup, mais pas exactement le temps d’access. Son timing inclut le bouclage sur les tableaux et les listes. Étant donné que je suis également venu avec une troisième méthode que je voulais tester, un «dictionnaire», juste pour comparer, j’ai étendu le code de test hist.

D’abord, je fais un test en utilisant une constante, ce qui me donne un certain temps, y compris la boucle. C’est un timing “nu”, à l’exclusion de l’access réel. Ensuite, je fais un test pour accéder à la structure du sujet, cela me donne un temps et des délais, un bouclage et un access réel.

La différence entre la synchronisation «nue» et la temporisation «induite» me donne une indication du timing de «l’access à la structure».

Mais quelle est la précision de ce timing? Pendant les tests, les fenêtres feront des tranches de temps. Je n’ai aucune information sur le découpage du temps mais je suppose qu’il est dissortingbué uniformément pendant le test et dans l’ordre de quelques dizaines de millisecondes, ce qui signifie que la précision du chronométrage devrait être de l’ordre de +/- 100 msec. Une estimation un peu approximative? Quoi qu’il en soit, une source d’erreur systématique.

De plus, les tests ont été effectués en mode ‘Debug’ sans optimalisation. Sinon, le compilateur pourrait changer le code de test réel.

Donc, j’obtiens deux résultats, un pour une constante, marqué “(c)”, et un pour l’access marqué “(n)” et la différence “dt” m’indique combien de temps dure l’access réel.

Et ce sont les résultats:

  Dictionary(c)/for: 1205ms (600000000) Dictionary(n)/for: 8046ms (589725196) dt = 6841 List(c)/for: 1186ms (1189725196) List(n)/for: 2475ms (1779450392) dt = 1289 Array(c)/for: 1019ms (600000000) Array(n)/for: 1266ms (589725196) dt = 247 Dictionary[key](c)/foreach: 2738ms (600000000) Dictionary[key](n)/foreach: 10017ms (589725196) dt = 7279 List(c)/foreach: 2480ms (600000000) List(n)/foreach: 2658ms (589725196) dt = 178 Array(c)/foreach: 1300ms (600000000) Array(n)/foreach: 1592ms (589725196) dt = 292 dt +/-.1 sec for foreach Dictionary 6.8 7.3 List 1.3 0.2 Array 0.2 0.3 Same test, different system: dt +/- .1 sec for foreach Dictionary 14.4 12.0 List 1.7 0.1 Array 0.5 0.7 

Avec de meilleures estimations des erreurs de synchronisation (comment supprimer l’erreur de mesure systématique due au découpage du temps?), On pourrait en dire plus sur les résultats.

Il semble que List / foreach ait l’access le plus rapide, mais la surcharge le tue.

La différence entre List / for et List / foreach est étrange. Peut-être qu’un encaissement est impliqué?

De plus, l’access à un tableau n’a pas d’importance si vous utilisez une boucle for ou une boucle foreach . Le timing et sa précision rendent les résultats «comparables».

Utiliser un dictionnaire est de loin le plus lent, je ne l’ai considéré que parce que sur le côté gauche (l’indexeur) j’ai une liste fragmentée d’entiers et non une plage telle qu’elle est utilisée dans ces tests.

Voici le code de test modifié.

 Dictionary dict = new Dictionary(6000000); List list = new List(6000000); Random rand = new Random(12345); for (int i = 0; i < 6000000; i++) { int n = rand.Next(5000); dict.Add(i, n); list.Add(n); } int[] arr = list.ToArray(); int chk = 0; Stopwatch watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = dict.Count; for (int i = 0; i < len; i++) { chk += 1; // dict[i]; } } watch.Stop(); long c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Dictionary(c)/for: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = dict.Count; for (int i = 0; i < len; i++) { chk += dict[i]; } } watch.Stop(); long n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Dictionary(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += 1; // list[i]; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(c)/for: {0}ms ({1})", c_dt, chk); watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { int len = list.Count; for (int i = 0; i < len; i++) { chk += list[i]; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += 1; // arr[i]; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Array(c)/for: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { for (int i = 0; i < arr.Length; i++) { chk += arr[i]; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Array(n)/for: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += 1; // dict[i]; ; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine("Dictionary[key](c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in dict.Keys) { chk += dict[i]; ; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Dictionary[key](n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += 1; // i; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in list) { chk += i; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine(" List(n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += 1; // i; } } watch.Stop(); c_dt = watch.ElapsedMilliseconds; Console.WriteLine(" Array(c)/foreach: {0}ms ({1})", c_dt, chk); chk = 0; watch = Stopwatch.StartNew(); for (int rpt = 0; rpt < 100; rpt++) { foreach (int i in arr) { chk += i; } } watch.Stop(); n_dt = watch.ElapsedMilliseconds; Console.WriteLine("Array(n)/foreach: {0}ms ({1})", n_dt, chk); Console.WriteLine("dt = {0}", n_dt - c_dt); 

Dans de brefs tests, j’ai trouvé une combinaison des deux plus efficace dans ce que j’appellerais des mathématiques raisonnablement intensives:

Type: List

Heure: 00: 00: 05.1861300

Type: List>

Heure: 00: 00: 05.7941351

Type: double[rows * columns]

Heure: 00: 00: 06.0547118

Exécuter le code:

 int rows = 10000; int columns = 10000; IMasortingx Masortingx = new IMasortingx(rows, columns); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int r = 0; r < Matrix.Rows; r++) for (int c = 0; c < Matrix.Columns; c++) Matrix[r, c] = Math.E; for (int r = 0; r < Matrix.Rows; r++) for (int c = 0; c < Matrix.Columns; c++) Matrix[r, c] *= -Math.Log(Math.E); stopwatch.Stop(); TimeSpan ts = stopwatch.Elapsed; Console.WriteLine(ts.ToString()); 

Je souhaite que nous ayons eu quelques classes de masortingces accélérées par matériel comme l’équipe .NET l’a fait avec la classe System.Numerics.Vectors !

C # pourrait être le meilleur ML Language avec un peu plus de travail dans ce domaine!