Wie funktioniert String.Contains? [Duplikat]

7

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.

    
Ash Burlaczenko 22.09.2010, 13:08
quelle

7 Antworten

17

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.

    
Hans Passant 22.09.2010, 14:28
quelle
4

"Im Allgemeinen wird der Algorithmus schneller, wenn der gesuchte Schlüssel länger wird"

Ссылка

    
soniiic 22.09.2010 13:12
quelle
2

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.

    
AnthonyLambert 22.09.2010 13:16
quelle
1

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:

  • Durchlaufen Sie den gesamten Inhalt der Datei (dies kann File-IO-Überlegungen enthalten oder nicht, die Sie möglicherweise separat testen möchten).
  • Überprüfen Sie String.Contains() für jede Zeile in der Datei.
  • "Mach Sachen", wenn es eine Übereinstimmung gibt

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.

  1. Messen Sie die Zeit, die Sie brauchen, um einfach durch die gesamte Datei zu blättern, ohne etwas anderes zu tun. Dies isoliert Ihren Schleifen- und IO-Code, damit Sie sehen können, wie gut er funktioniert.
  2. Als nächstes fügen Sie nur den String-Vergleich ( String.Contains ) hinzu und messen Sie die Gesamtzeit, die mit dieser hinzugefügten Zeit benötigt wird.
  3. Zuletzt fügen Sie den Code "do sachen" hinzu und messen Sie die Gesamtzeit mit dieser hinzugefügten.

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.

    
Ben McCormack 22.09.2010 14:40
quelle
1

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:

%Vor%

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.

    
JulianR 26.09.2010 01:20
quelle
0

Die String.Contains-Methode gibt true nur dann zurück, wenn diese Zeichenfolge die angegebene Folge von char-Werten enthält.

Es wird im Grunde verwendet, um die Unterzeichenfolge in der Zeichenfolge zu überprüfen.

Ссылка

    
Adi_aks 22.09.2010 13:14
quelle
0

Contains , wie alle String-Suchmethoden (glaube ich), führt schließlich zur externen Methode InternalFindNLSStringEx - was auch immer das ist, es ist ziemlich unpassierbar.

    
annakata 22.09.2010 13:21
quelle

Tags und Links