Angenommen, Sie benötigen eine Liste / ein Array von Ganzzahlen, die Sie häufig iterieren müssen, und ich meine extrem oft. Die Gründe können variieren, aber sagen wir, es befindet sich im Herzen der innersten Schleife einer Verarbeitung mit hohem Volumen.
Im Allgemeinen würde man sich aufgrund ihrer flexiblen Größe für die Verwendung von Listen (Listen) entscheiden. Darüber hinaus behauptet die msdn-Dokumentation, dass Listen ein Array intern verwenden und genauso schnell arbeiten sollten (ein kurzer Blick mit Reflector bestätigt dies). Trotzdem ist ein gewisser Aufwand erforderlich.
Hat jemand das tatsächlich gemessen? Würde das 6-malige Durchlaufen einer Liste dieselbe Zeit in Anspruch nehmen wie ein Array?
T[]
vs.List<T>
kann einen großen Unterschied in der Leistung machen. Ich habe gerade eine extrem (verschachtelte) schleifenintensive Anwendung optimiert, um unter .NET 4.0 von Listen zu Arrays zu wechseln. Ich hatte eine Verbesserung von 5% bis 10% erwartet, aber eine Beschleunigung von über 40% erreicht! Keine anderen Änderungen als direkt von der Liste zum Array zu wechseln. Alle Aufzählungen wurden mitforeach
Aussagen durchgeführt. Basierend auf Marc Gravells Antwort sieht es so aus, als wäre esforeach
mitList<T>
besonders schlecht.Antworten:
Sehr einfach zu messen ...
In einer kleinen Anzahl von Verarbeitungscodes mit engen Schleifen, bei denen ich weiß, dass die Länge festgelegt ist, verwende ich Arrays für dieses zusätzliche kleine Stück Mikrooptimierung. Arrays können geringfügig schneller sein, wenn Sie den Indexer / für das Formular verwenden. IIRC ist jedoch der Ansicht, dass dies vom Datentyp im Array abhängt. Aber es sei denn , Sie brauchen , um Mikro-optimize, halten Sie es einfach und verwenden
List<T>
usw.Dies gilt natürlich nur, wenn Sie alle Daten lesen. Ein Wörterbuch wäre für schlüsselbasierte Suchvorgänge schneller.
Hier sind meine Ergebnisse mit "int" (die zweite Zahl ist eine Prüfsumme, um zu überprüfen, ob alle die gleiche Arbeit geleistet haben):
(bearbeitet, um den Fehler zu beheben)
basierend auf dem Prüfstand:
quelle
Zusammenfassung:
Array muss verwendet werden:
Liste muss verwendet werden:
LinkedList muss Folgendes verwenden:
Mehr Details:
Viel mehr Details:
https://stackoverflow.com/a/29263914/4423545
quelle
Ich denke, die Leistung wird ziemlich ähnlich sein. Der Overhead, der bei der Verwendung einer Liste im Vergleich zu einem Array anfällt, ist IMHO, wenn Sie Elemente zur Liste hinzufügen und wenn die Liste die Größe des Arrays erhöhen muss, das intern verwendet wird, wenn die Kapazität des Arrays erreicht ist.
Angenommen, Sie haben eine Liste mit einer Kapazität von 10, dann erhöht die Liste ihre Kapazität, sobald Sie das 11. Element hinzufügen möchten. Sie können die Auswirkungen auf die Leistung verringern, indem Sie die Kapazität der Liste auf die Anzahl der darin enthaltenen Elemente initialisieren.
Aber um herauszufinden, ob das Durchlaufen einer Liste genauso schnell ist wie das Durchlaufen eines Arrays, warum vergleichen Sie es nicht?
Auf meinem System; Das Iterieren über das Array dauerte 33 ms. Das Durchlaufen der Liste dauerte 66 ms.
Um ehrlich zu sein, hatte ich nicht erwartet, dass die Variation so groß sein würde. Also habe ich meine Iteration in eine Schleife gesetzt: Jetzt führe ich beide Iterationen 1000 Mal aus. Die Ergebnisse sind:
Jetzt ist die Variation nicht mehr so groß, aber immer noch ...
Daher habe ich .NET Reflector gestartet und der Getter des Indexers der List-Klasse sieht folgendermaßen aus:
Wie Sie sehen können, führt die Liste bei Verwendung des Indexers der Liste eine Überprüfung durch, ob Sie die Grenzen des internen Arrays nicht überschreiten. Dieser zusätzliche Scheck ist kostenpflichtig.
quelle
Wenn Sie nur einen einzigen Wert aus einem der beiden Werte (nicht in einer Schleife) erhalten, überprüfen beide die Grenzen (Sie befinden sich im verwalteten Code, denken Sie daran). Die Liste führt dies nur zweimal aus. In den Anmerkungen später erfahren Sie, warum dies wahrscheinlich keine große Sache ist.
Wenn Sie Ihre eigene für verwenden (int int i = 0; i <x. [Länge / Anzahl]; i ++), ist der Hauptunterschied wie folgt:
Wenn Sie foreach verwenden, ist der Hauptunterschied wie folgt:
Die Überprüfung der Grenzen ist oft keine große Sache (insbesondere, wenn Sie eine CPU mit einer tiefen Pipeline- und Verzweigungsvorhersage verwenden - die Norm für die meisten dieser Tage), aber nur Ihre eigene Profilerstellung kann Ihnen sagen, ob dies ein Problem ist. Wenn Sie sich in Teilen Ihres Codes befinden, in denen Sie Heap-Zuweisungen vermeiden (gute Beispiele sind Bibliotheken oder in Hashcode-Implementierungen), können Sie diese Gefahr vermeiden, indem Sie sicherstellen, dass die Variable als List not IList eingegeben wird. Wie immer Profil, wenn es darauf ankommt.
quelle
[ Siehe auch diese Frage ]
Ich habe Marc's Antwort so geändert, dass sie tatsächliche Zufallszahlen verwendet und in allen Fällen die gleiche Arbeit leistet.
Ergebnisse:
Kompiliert als Release unter VS 2008 SP1. Wird ohne Debugging auf einem [email protected], .NET 3.5 SP1 ausgeführt.
Code:
quelle
Die Messungen sind gut, aber Sie werden signifikant unterschiedliche Ergebnisse erhalten, je nachdem, was Sie genau in Ihrer inneren Schleife tun. Messen Sie Ihre eigene Situation. Wenn Sie Multithreading verwenden, ist dies allein keine triviale Aktivität.
quelle
Wenn Sie einige komplexe Berechnungen innerhalb der Schleife durchführen, ist die Leistung des Array-Indexers im Vergleich zum Listenindexer möglicherweise so gering, dass es letztendlich keine Rolle spielt.
quelle
Hier ist eines, das Wörterbücher verwendet, IEnumerable:
quelle
Versuchen Sie nicht, die Kapazität durch Erhöhen der Anzahl der Elemente zu erhöhen.
Performance
quelle
Ich befürchtete, dass die in anderen Antworten veröffentlichten Benchmarks dem Compiler noch Raum lassen würden, Schleifen zu optimieren, zu eliminieren oder zusammenzuführen, und schrieb eine, die:
Das Ergebnis ist, dass ein direktes Array eine um 250% bessere Leistung aufweist als ein Zugriff auf ein in eine IList eingeschlossenes Array:
Hier ist der Code:
quelle
Da List <> Arrays intern verwendet, sollte die Grundleistung dieselbe sein. Zwei Gründe, warum die Liste möglicherweise etwas langsamer ist:
Um zu überprüfen, ob es für Sie einen Unterschied macht, passen Sie die angegebenen Timing-Funktionen wahrscheinlich am besten an eine Liste der Größe an, die Sie verwenden möchten, und sehen Sie, wie die Ergebnisse für Ihren Sonderfall aussehen.
quelle
Da ich eine ähnliche Frage hatte, bekam ich einen schnellen Start.
Meine Frage ist etwas spezifischer: Was ist die schnellste Methode für eine reflexive Array-Implementierung?
Die von Marc Gravell durchgeführten Tests zeigen viel, aber nicht genau das Timing des Zugriffs. Sein Timing beinhaltet auch das Durchlaufen der Arrays und Listen. Da ich auch eine dritte Methode gefunden habe, die ich testen wollte, ein 'Wörterbuch', um sie zu vergleichen, habe ich den Hist-Testcode erweitert.
Firts, ich mache einen Test mit einer Konstanten, die mir ein bestimmtes Timing einschließlich der Schleife gibt. Dies ist ein "nackter" Zeitpunkt, der den tatsächlichen Zugriff ausschließt. Dann mache ich einen Test mit Zugriff auf die Subjektstruktur, dies gibt mir und Overhead inklusive Timing, Looping und tatsächlichen Zugriff.
Der Unterschied zwischen "nacktem" Timing und "Overhead-eingeschlossenem" Timing gibt mir einen Hinweis auf das "Strukturzugriff" -Zeitpunkt.
Aber wie genau ist dieses Timing? Während des Tests werden die Fenster einige Zeit in Scheiben geschnitten, um die Sicherheit zu gewährleisten. Ich habe keine Informationen über das Time Slicing, aber ich gehe davon aus, dass es während des Tests gleichmäßig verteilt ist und in der Größenordnung von zehn ms liegt, was bedeutet, dass die Genauigkeit für das Timing in der Größenordnung von +/- 100 ms oder so liegen sollte. Eine etwas grobe Schätzung? Auf jeden Fall eine Quelle für einen systematischen Mearure-Fehler.
Außerdem wurden die Tests im Debug-Modus ohne Optimierung durchgeführt. Andernfalls kann der Compiler den tatsächlichen Testcode ändern.
Ich erhalte also zwei Ergebnisse, eines für eine Konstante mit der Bezeichnung '(c)' und eines für den mit '(n)' gekennzeichneten Zugriff. Die Differenz 'dt' gibt an, wie viel Zeit der tatsächliche Zugriff benötigt.
Und das sind die Ergebnisse:
Mit besseren Schätzungen der Zeitfehler (wie kann der systematische Messfehler aufgrund von Zeitscheiben beseitigt werden?) Könnte mehr über die Ergebnisse gesagt werden.
Es sieht so aus, als hätte List / foreach den schnellsten Zugriff, aber der Overhead bringt ihn um.
Der Unterschied zwischen List / for und List / foreach ist seltsam. Vielleicht ist etwas Geld erforderlich?
Für den Zugriff auf ein Array spielt es keine Rolle, ob Sie eine
for
Schleife oder eineforeach
Schleife verwenden. Die Timing-Ergebnisse und ihre Genauigkeit machen die Ergebnisse "vergleichbar".Die Verwendung eines Wörterbuchs ist bei weitem am langsamsten. Ich habe es nur in Betracht gezogen, weil ich auf der linken Seite (dem Indexer) eine spärliche Liste von Ganzzahlen habe und keinen Bereich, wie er in diesen Tests verwendet wird.
Hier ist der geänderte Testcode.
quelle
In einigen kurzen Tests habe ich festgestellt, dass eine Kombination aus beiden besser ist, was ich als einigermaßen intensive Mathematik bezeichnen würde:
Art:
List<double[]>
Art:
List<List<double>>
Art:
double[rows * columns]
Ausführen des Codes:
Ich wünschte, wir hätten einige erstklassige Hardware Accelerated Matrix-Klassen, wie sie das .NET-Team mit dem gemacht hat
System.Numerics.Vectors
Klasse gemacht hat!C # könnte die beste ML-Sprache mit etwas mehr Arbeit in diesem Bereich sein!
quelle