Ist String.Contains () schneller als String.IndexOf ()?

111

Ich habe einen Zeichenfolgenpuffer von ca. 2000 Zeichen und muss den Puffer überprüfen, wenn er eine bestimmte Zeichenfolge enthält.
Führt die Prüfung in einer ASP.NET 2.0-Webanwendung für jede Webanforderung durch.

Weiß jemand, ob die String.Contains-Methode eine bessere Leistung als die String.IndexOf-Methode aufweist ?

    // 2000 characters in s1, search token in s2
    string s1 = "Many characters. The quick brown fox jumps over the lazy dog"; 
    string s2 = "fox";
    bool b;
    b = s1.Contains(s2);
    int i;
    i = s1.IndexOf(s2);

Lustige Tatsache

Kb.
quelle
14
Wenn Sie dies eine Milliarde Mal pro Webanforderung tun müssen, würde ich anfangen, mir solche Dinge anzuschauen. In jedem anderen Fall würde ich mich nicht darum kümmern, da die Zeit, die in beiden Methoden verbracht wird, höchstwahrscheinlich unglaublich unbedeutend sein wird, verglichen mit dem Empfang der HTTP-Anfrage an erster Stelle.
mookid8000
2
Einer der Schlüssel zur Optimierung ist das Testen, anstatt anzunehmen, da dies von vielen Faktoren wie der .NET-Version, dem Betriebssystem, der Hardware, der Variation der Eingabe usw. abhängen kann. In vielen Fällen werden Testergebnisse von anderen durchgeführt kann auf Ihrem System sehr unterschiedlich sein.
Slai

Antworten:

174

ContainsAnrufe IndexOf:

public bool Contains(string value)
{
    return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Welche Aufrufe CompareInfo.IndexOf, welche letztendlich eine CLR-Implementierung verwenden.

Wenn Sie sehen möchten, wie Zeichenfolgen in der CLR verglichen werden, wird dies angezeigt (suchen Sie nach CaseInsensitiveCompHelper ).

IndexOf(string)hat keine Optionen und Contains()verwendet einen Ordnungsvergleich (einen byteweisen Vergleich, anstatt zu versuchen, einen intelligenten Vergleich durchzuführen, z. B. e mit é).

So IndexOfwird geringfügig schneller (in der Theorie) als IndexOfgerade auf eine String - Suche geht mit FindNLSString von kernel32.dll (die Kraft des Reflektors!).

Aktualisiert für .NET 4.0 - IndexOf verwendet keinen Ordnungsvergleich mehr und kann daher schneller sein. Siehe Kommentar unten.

Chris S.
quelle
3
Diese Antwort ist bei weitem nicht richtig, werfen Sie einen Blick hier auf stackoverflow.com/posts/498880/revisions für die Erklärung
pzaj
55
Meine Antwort ist 7 Jahre alt und basiert auf dem .NET 2-Framework. Version 4 IndexOf()verwendet tatsächlich StringComparison.CurrentCultureund Contains()verwendet, StringComparison.Ordinalwas schneller sein wird. Aber die Geschwindigkeitsunterschiede, über die wir sprechen, sind wirklich winzig - der Punkt ist, dass einer den anderen aufruft und Contains besser lesbar ist, wenn Sie den Index nicht benötigen. Mit anderen Worten, mach dir keine Sorgen.
Chris S
21

Wahrscheinlich wird es überhaupt keine Rolle spielen. Lesen Sie diesen Beitrag über Coding Horror;): http://www.codinghorror.com/blog/archives/001218.html

Gonzalo Quero
quelle
4
Saugen wir uns an den Chef, sind wir ...? : D Sie haben jedoch Recht, verglichen mit der Zeit, die für die Bearbeitung einer http-Anfrage benötigt wird, ist das einmalige Durchsuchen einer kurzen Zeichenfolge nicht von Bedeutung.
Geflügel
Eine sehr unterhaltsame Lektüre, aber es stört mich, dass seine anfängliche Beschwerde über die Verkettung die Speichernutzung ist. Dann testet er nur die Zeit, die er mit den verschiedenen Möglichkeiten zum Kombinieren von Zeichenfolgen verbracht hat.
Sab669
11

Contains (s2) ist viele Male (auf meinem Computer 10 Mal) schneller als IndexOf (s2), da Contains StringComparison.Ordinal verwendet, das schneller ist als die kultursensitive Suche, die IndexOf standardmäßig durchführt (dies kann sich jedoch in .net 4.0 ändern : http: //davesbox.com/archive/2008/11/12/breaking-changes-to-the-string-class.aspx ).

Enthält in meinen Tests genau die gleiche Leistung wie IndexOf (s2, StringComparison.Ordinal)> = 0, ist jedoch kürzer und macht Ihre Absicht klar.

ggf31416
quelle
2
Die Änderungen in .NET 4.0 wurden anscheinend vor RTM rückgängig gemacht, sodass ich mich nicht zu sehr auf diesen Artikel verlassen würde. Blogs.msdn.com/bclteam/archive/2008/11/04/…
Stephen Kennedy
7

Ich führe einen echten Fall durch (im Gegensatz zu einem synthetischen Benchmark)

 if("=,<=,=>,<>,<,>,!=,==,".IndexOf(tmps)>=0) {

gegen

 if("=,<=,=>,<>,<,>,!=,==,".Contains(tmps)) {

Es ist ein wichtiger Teil meines Systems und wird 131.953 Mal ausgeführt (danke DotTrace).

Wie schockierend die Überraschung auch sein mag , das Ergebnis ist das Gegenteil von dem, was erwartet wurde

  • Index von 533 ms.
  • Enthält 266ms.

: - /

Net Framework 4.0 (aktualisiert am 13-02-2012)

Magallane
quelle
1
weil INTist viel größer als BOOLund IndexOf>=0verursachen einen weiteren Schritt
Eric Yin
3
Sie haben vergessen, "StringComparison.Ordinal" zu verwenden
Davi Fiamenghi
6

Wenn Sie Reflector verwenden, können Sie sehen, dass Contains mit IndexOf implementiert wird. Hier ist die Implementierung.

public bool Contains(string value)
{
   return (this.IndexOf(value, StringComparison.Ordinal) >= 0);
}

Contains ist also wahrscheinlich etwas langsamer als der direkte Aufruf von IndexOf, aber ich bezweifle, dass dies für die tatsächliche Leistung von Bedeutung sein wird.

Brian Rasmussen
quelle
1
Ja, aber um indexof als Bool zu verwenden, müsste er den Vergleich außerhalb der Funktion durchführen. Das würde höchstwahrscheinlich das gleiche Ergebnis wie Contains liefern, nicht wahr?
Gonzalo Quero
1
Wahrscheinlich, aber Sie speichern einen Methodenaufruf (es sei denn, er kann eingebunden werden). Wie gesagt, es wird wahrscheinlich nie von Bedeutung sein.
Brian Rasmussen
6

Wenn Sie Ihren Code wirklich mikrooptimieren möchten, ist Benchmarking immer der beste Ansatz.

Das .net-Framework verfügt über eine hervorragende Stoppuhr-Implementierung - System.Diagnostics.Stopwatch

Andrew Harry
quelle
Es ist das Beste, aber wenn Sie einen schnellen Ansatz wünschen, drücken Sie einfach die Pause-Taste in einer Debug-Sitzung. Die Codesteuerung wird wahrscheinlich im langsamsten Teil in ungefähr 50% der Fälle angehalten .
Jeremy Thompson
4

Aus einer kleinen Lektüre geht hervor, dass die String.Contains-Methode unter der Haube einfach String.IndexOf aufruft. Der Unterschied besteht darin, dass String.Contains einen Booleschen Wert zurückgibt, während String.IndexOf eine Ganzzahl mit (-1) zurückgibt, die angibt, dass der Teilstring nicht gefunden wurde.

Ich würde vorschlagen, einen kleinen Test mit etwa 100.000 Iterationen zu schreiben und sich selbst davon zu überzeugen. Wenn ich raten würde, würde ich sagen, dass IndexOf vielleicht etwas schneller ist, aber wie gesagt, es ist nur eine Vermutung.

Jeff Atwood hat einen guten Artikel über Streicher in seinem Blog . Es geht mehr um Verkettung, kann aber dennoch hilfreich sein.

Mike Roosa
quelle
3

Gerade als Update habe ich einige Tests durchgeführt und vorausgesetzt, Ihre Eingabezeichenfolge ist ziemlich groß, dann ist parallel Regex die schnellste C # -Methode, die ich gefunden habe (vorausgesetzt, Sie haben mehr als einen Kern, wie ich mir vorstelle).

Zum Beispiel die Gesamtzahl der Übereinstimmungen abrufen -

needles.AsParallel ( ).Sum ( l => Regex.IsMatch ( haystack , Regex.Escape ( l ) ) ? 1 : 0 );

Hoffe das hilft!

Gary
quelle
1
Hallo Phild, in einem separaten Thread wurde dies mit einer Version von tomasp.net/articles/ahocorasick.aspx aktualisiert , die viel schneller ist, wenn sich Ihre Schlüsselwörter (Nadeln) nicht ändern.
Gary
2

Verwenden Sie eine Benchmark-Bibliothek, wie diesen jüngsten Streifzug von Jon Skeet , um sie zu messen.

Vorbehalt Emptor

Wie bei allen (Mikro-) Leistungsfragen hängt dies von den von Ihnen verwendeten Softwareversionen, den Details der überprüften Daten und dem Code ab, der den Anruf umgibt.

Wie bei allen (Mikro-) Leistungsfragen muss der erste Schritt darin bestehen, eine laufende Version zu erhalten, die leicht zu warten ist. Dann können Benchmarking, Profiling und Tuning auf die gemessenen Engpässe angewendet werden, anstatt zu raten.

David Schmitt
quelle
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
Mike Stockdale
Die verknüpfte Bibliothek ist nur eine von vielen und nicht der Hauptschwerpunkt der Antwort. Ich denke nicht, dass das Posten der Quelle oder Beschreibung der Bibliothek die Antwort, diese Seite oder die Welt verbessern würde.
David Schmitt
3
-1; Die Frage lautete: "Weiß jemand, ob die String.Contains-Methode eine bessere Leistung als die String.IndexOf-Methode aufweist?" - Ihre Antwort lautet "Verwenden Sie eine Benchmark-Bibliothek", was im Grunde bedeutet "Ich weiß nicht, machen Sie es selbst", "das hängt davon ab", was "Ich weiß nicht" bedeutet, und "Holen Sie sich eine laufende Version und ein laufendes Profil". , was auch bedeutet "Ich weiß nicht, mach es selbst". Dies ist keine "Gefahr" - bitte geben Sie eine Antwort auf die gestellte Frage , nicht auf Anleitungen - ihr Platz ist in Kommentaren .
-7

Für alle, die dies noch lesen, wird indexOf () auf den meisten Unternehmenssystemen wahrscheinlich eine bessere Leistung erzielen, da enthält () nicht mit dem IE kompatibel ist!

Zargontapel
quelle
11
neue OutOfScopeException () auslösen;
Raphaël