Ich habe eine Schleife in meinem Programm, die eine Zeile aus einer Datei erhält. Dann wird geprüft, ob die Zeile eine Zeichenkette enthält
%Vor%Es gibt mehr als 2 Millionen Zeilen in der Datei. Wenn ich also die Geschwindigkeit um 1/10 Millisekunden beschleunigen kann, würde ich bei jedem Durchlauf mehr als 3 Minuten sparen.
Also ... Eine Zeile ist 1000 Zeichen lang, ist es schneller, nach einer kurzen oder langen Zeichenfolge zu suchen, oder macht das keinen Unterschied?
%Vor%oder
%Vor%Vielen Dank im Voraus.
String.Contains () folgt einer qualvollen Route durch System.Globalization.CompareInfo in das CLR und das NLS-Support-Subsystem, wo ich mich gründlich verlaufen habe. Dies beinhaltet hochoptimierten Code mit beeindruckender Perf. Der einzige Weg, es schneller zu machen, ist durch den Aufruf der Standard-CRT-Funktion wcsstr, verfügbar in msvcrt.dll
%Vor%Gibt IntPtr.Zero zurück, wenn die Zeichenfolge nicht gefunden wurde. Ich habe einige Messungen durchgeführt, indem ich String.IndexOf () anstelle von Contains () verwendet habe, um die verschiedenen Optionen für den Vergleich von Zeichenfolgen zu testen. Alle Zeiten sind in Nanosekunden und suchen nach einer Zeichenfolge aus 7 Zeichen in einer Zeichenfolge von 60 Zeichen. Wenn die Saite nicht vorhanden ist, wird der schlechteste Fall gemessen. Das niedrigste Zeitlimit einer Stichprobe von 20 wurde verwendet:
%Vor%Sehr beeindruckende Zahlen und auf Augenhöhe mit dem, was Sie von diesen Funktionen erwarten würden. Die Funktion wcsstr () führt die gleiche Art von ordinalem Vergleich durch wie String.Compare (). Es ist nur 13% schneller, eine statistisch unbedeutende Verbesserung, da Real Perf sich aufgrund der CPU-Cache-Lokalität wahrscheinlich nicht an diese Messungen annähern wird. Ich kann nur schlussfolgern, dass Sie so schnell gehen, wie Sie erwarten können. Ob die leichte Verbesserung von wcsstr es wert ist, liegt an Ihnen.
Wenn .NET String.Contains den Boyer-Moore-Algorithmus verwendet, ist es schneller zu suchen eine längere Zeichenfolge.
Darf ich vorschlagen, dass, wenn Sie eine Datei mit Trennzeichen lesen, zum Beispiel jede Zeile eine Reihe von Textfeldern ist, die durch Kommata getrennt sind, so können Sie einige Suchzeiten sparen, indem Sie nicht von Position 0 in der Zeile suchen. t zum Beispiel vor Zeichen 40.
Es ist durchaus üblich, eine Zeile unter Verwendung der String Spilled-Funktion auf ein Trennzeichen zu splitten, das ein Array von Strings zurückgibt. Dann würden Sie nur innerhalb des Feldes suchen, in dem der Wert erscheinen könnte. Das wird auch schneller.
Wenn es darum geht, die Leistung zu steigern, möchten Sie sicherstellen, dass das, was Sie verbessern wollen, tatsächlich die Ursache für den Engpass ist. Ich würde damit beginnen, die Leistung der verschiedenen Teile in meinem Code zu profilieren und herauszufinden, welches Stück den größten Engpass darstellt.
Auf den ersten Blick sehe ich drei Hauptkomponenten dieses Prozesses, die sich zu profilieren lohnt:
String.Contains()
für jede Zeile in der Datei. Obwohl es große kommerzielle Profiler gibt, können Sie mit einem einfachen Timer (wie System.Diagnostics.Stopwatch
) in Ihrem Code beginnen, oder, wenn der Prozess wirklich lang ist, einfach die Uhr verwenden, um die Zeit zu messen.
Messen Sie die Zeit für jeden der folgenden Punkte.
String.Contains
) hinzu und messen Sie die Gesamtzeit, die mit dieser hinzugefügten Zeit benötigt wird. Sie können jetzt die Kosten für das Hinzufügen in jeder Komponente vergleichen, um herauszufinden, wie teuer diese Komponente ist und ob Sie sie verbessern müssen. Angenommen, Sie haben die folgenden Zeiten aufgezeichnet:
%Vor%Wenn man diese (falschen) Zahlen betrachtet, ist der teuerste Teil des Prozesses der Schleifen- und IO-Code, und hier würde ich versuchen, die Leistung zu erhöhen. Da der "Do Stuff" -Teil 25 Sekunden zur Gesamtausführungszeit hinzugefügt hat, würde ich mir diesen Code ansehen, um zu sehen, ob es etwas gibt, das ich verbessern könnte. Zu guter Letzt würde ich den Stringvergleich betrachten.
Natürlich sind die von mir bereitgestellten Zeitmessungen fiktiv, aber Sie können die gleichen Schritte auf Ihre Leistungsprofile in Ihrer Anwendung anwenden. Der Schlüssel besteht darin, die größten Kosten zu identifizieren und diese zuerst zu reduzieren.
Zu meiner Überraschung ist ein kompiliertes Regex
tatsächlich viel, viel schneller als Contains
. Die Kosten für das Kompilieren sind natürlich nur dann wert, wenn Sie mehrmals nach derselben Zeichenkette suchen. Aber wenn es so ist, ist es mehr als zweimal schneller. Probieren Sie es selbst aus:
Ich habe immer noch nicht herausgefunden, wie schnell es sein kann, wenn man sich die kompilierte Assembly anschaut, es ist ein verschleiertes Durcheinander von switch
-Aussagen. Aber es ist schnell, wirklich schnell.
Tags und Links string c# performance