2009-12-16 6 views
9

Während meine Anwendung entwickeln ich auf einige Vergleich Sachen hergekommen war es:, die schnell Vergleich: Convert.ToInt32 (String) == intValue oder String == intValue.ToString()

string str = "12345"; 
    int j = 12345; 
    if (str == j.ToString()) 
    { 
     //do my logic 
    } 

Ich dachte dass das obige Material auch mit getan werden kann:

string str = "12345"; 
    int j = 12345; 
    if (Convert.ToInt32(str) == j) 
    { 
     //do my logic 
    } 

So entwickelte ich ein Beispielcode zu testen, in Bezug auf die Leistung, die man besser

 var iterationCount = 1000000; 
     var watch = new Stopwatch(); 
     watch.Start(); 
     string str = "12345"; 
     int j = 12345; 
     for (var i = 0; i < iterationCount; i++) 
     { 
      if (str == j.ToString()) 
      { 
       //do my logic 
      } 
     } 
     watch.Stop(); 

Und zweitens ein:

var iterationCount = 1000000; 
    var watch = new Stopwatch(); 
    watch.Start(); 
    string str = "12345"; 
    int j = 12345; 
    for (var i = 0; i < iterationCount; i++) 
    { 
     if (Convert.ToInt32(str) == j) 
     { 
      //do my logic 
     } 
    } 
    watch.Stop(); 

Auf den beiden Prüfungen laufen fand ich die obigen Tests wurden verstrichen fast die gleiche Zeit. Ich würde gerne diskutieren, welches ist der bessere Ansatz? Und gibt es einen anderen Ansatz als zwei über zwei?

Antwort

12

Ihr Test ist grundlegend fehlerhaft. Der Compiler und die Laufzeit sind wirklich clevere Biester und optimieren den Code sowohl zur Kompilierzeit als auch zur Laufzeit (JIT-ing). In diesem Fall tun Sie die gleiche Sache jedes Mal, die vom Compiler entdeckt und optimiert werden, daher wird das Timing für jede Methode ähnlich sein.

Versuchen Sie, diese Version (Ich habe nur .Net 2.0, also die geringen Veränderungen):

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Diagnostics; 

namespace ToStringTest 
{ 
    class Program 
    { 
     const int 
      iterationCount = 1000000; 

     static TimeSpan Test1() 
     { 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      string str = "12345"; 
      int j = 12345; 
      for (int i = 0; i < iterationCount; i++) 
      { 
       if (str == i.ToString()) 
       { 
        //do my logic 
       } 
      } 
      watch.Stop(); 
      return watch.Elapsed; 
     } 

     static TimeSpan Test2() 
     { 
      Stopwatch watch = new Stopwatch(); 
      watch.Start(); 
      string str = "12345"; 
      int j = 12345; 
      for (int i = 0; i < iterationCount; i++) 
      { 
       if (Convert.ToInt32(i) == j) 
       { 
        //do my logic 
       } 
      } 
      watch.Stop(); 
      return watch.Elapsed; 
     } 

     static void Main(string[] args) 
     { 
      Console.WriteLine("ToString = " + Test1().TotalMilliseconds); 
      Console.WriteLine("Convert = " + Test2().TotalMilliseconds); 
     } 
    } 
} 

und Sie werden einen großen Unterschied zu sehen. Einer ist zwei Größenordnungen schneller als der andere. Und es ist wirklich offensichtlich, welches es ist.

Sie müssen wissen, was die verschiedenen Operationen tun, um zu wissen, was wesentlich schneller ist.

einen String in einen int Konvertierung erfordert:

total = 0 
for each character in string 
    total = total * 10 + value of charater 

und die ToString erfordert:

string = "" 
while value != 0 
    string.AddToFront value % 10 
    value /= 10 

Multiplikation ist viel einfacher und schneller, für eine CPU als Abteilung zu tun. Angesichts der Wahl eines Algorithmus mit vielen Multiplikationen gegenüber einem Algorithmus mit vielen Divisionen, immer für den ersten gehen, da es immer schneller sein wird.

Dann gibt es den Vergleich, ein int - int Vergleich ist einfach, laden Sie jeden Wert in ein Register und vergleichen Sie - ein paar Maschinenanweisungen und Sie sind fertig. Ein Vergleich zwischen zwei Strings erfordert das Testen jedes Zeichens in den Strings nacheinander - in dem Beispiel, das Sie angegeben haben, war es 5 Bytes (ein int ist wahrscheinlich 4 Bytes), was mehr Speicherzugriffe ist.

2

Wenn Leistung fast identisch ist, gehen Sie mit der Version, die besser lesbar ist.

Persönlich finde ich die .ToString() Ansatz, um leichter zu verstehen und weniger anfällig für mögliche Casting-Probleme, die der andere Ansatz hat.

6

Ich bevorzuge i.ToString() == str da nichts garantiert, dass Convert.ToInt32(str) nicht fehlschlägt.

+3

Wenn "000123"! = 123, ist dies definitiv besser. –

3

Huch, Sie zeigen Ihre Domänenlogik als innerhalb Ihrer Profiling-Schleife, so dass Sie nicht den Zeitunterschied zwischen den Convert und ToString Versionen Ihres Codes getestet haben; Sie haben die kombinierte Zeit der Konvertierung und die Ausführung Ihrer Geschäftslogik getestet. Wenn Ihre Geschäftslogik langsam ist und die Conversion-Zeit dominiert, werden Sie natürlich in jeder Version die gleiche Zeit sehen.

Jetzt, mit dem aus dem Weg, sogar Sorgen darüber, bis Sie wissen, dass es ein Performance-Engpass ist, ist vorzeitige Optimierung. Insbesondere, wenn die Ausführung der Domänenlogik die Konvertierungszeit dominiert, spielt der Unterschied zwischen den beiden Faktoren keine Rolle. Wählen Sie also den, der am besten lesbar ist.

Jetzt, für welche Version zu verwenden: Sie müssen zunächst genau angeben, was Sie testen. Was sind deine Eingaben? Wird "007" jemals eine Eingabe sein? Ist "007" anders als die ganze Zahl 7? Wird "1.024" jemals ein Input sein? Gibt es Bedenken hinsichtlich der Lokalisierung?

+0

Ich habe nicht mit Domain-Logik in meinem Profil getestet, es war nur ein Kommentar darin geschrieben, wie ich gezeigt habe. – Raghav

+0

Sie zeigen '// tue meine Logik'. Jeder wird das so interpretieren, wie Sie Ihre Logik tun, aber wollen uns nicht die Details davon geben, nicht dass Sie die Logik auskommentiert haben. Um es klarzustellen, wäre es besser, den Test als 'bool b = Convert 'zu schreiben.ToInt32 (str) == j; 'usw. – jason

+0

@Raghav Khunger: Auch wenn Sie die Leistung der beiden Methoden getestet haben, ohne Ihre Domänenlogik auszuführen, bleibt meine Aussage: Machen Sie sich keine Gedanken darüber, bis Sie wissen, dass es eine ist Performance-Engpass. Geben Sie stattdessen vollständig an, was Sie implementieren möchten, und schreiben Sie den lesbarsten wartbaren Code, der den Job ausführt. – jason

0

Gut für Anfänger der erste, der das int in eine Zeichenfolge konvertiert, wird keinen Fehler auslösen, wenn die Zeichenfolge, mit der der Int verglichen wird, nicht in ein int konvertierbar ist.

Wenn Sie eine Menge von Tests in einem Batch-Konvertierung in eine Zeichenfolge durchführen, wird das Problem der potenziell Ausnahmen zu beseitigen, wegen Konvertierungsfehler zu entfernen. Das Aufheben von Ausnahmen benötigt Zeit und würde den zweiten Test verlangsamen.

13

Nun - Leistung sollte nicht das Einzige sein, worauf es ankommt.

Sie sollten fragen, ob Sie den tatsächlichen Wert oder nur die Darstellung der Zahl vergleichen möchten.

Nehmen Sie das folgende Beispiel: Ist "00001" gleich 1? Wenn Sie möchten, dass die Zeichenkette mit Int.TryParse in Kombination in int konvertiert wird, und vergleichen Sie sie dann.

Je nach lokalen Einstellungen kann es auch andere Unterschiede geben. Vielleicht hat der Benutzer festgelegt, Zahlen wie "1.000.000" zu formatieren - wenn Sie diese Zeichenfolge mit 1000000.ToString() vergleichen würden, wäre das Ergebnis falsch.

2

Semantik ist ein wenig anders. "01" == 1.ToString() ist false, 1 == Convert.ToInt32("01") ist wahr.

Wenn das Parsing fehlschlagen kann (Die Zeichenfolge ist keine gültige Zahl), dann ist Int32.TryParse schneller als Convert.ToInt32() zu verwenden.

0

Okay, i bewegen weiter einen Schritt voraus und Test auf diese Weise:

int j = 123; 
    for (var i = 0; i < iterationCount; i++) 
    { 
     j.ToString(); 
    } 

zweite: String str = "123";

 for (var i = 0; i < iterationCount; i++) 
     { 
      Convert.ToInt32(str); 
     } 

In diesem Fall habe ich jedes Mal, zweite gefunden wird etwas besser durchführen. In meinem Fall wäre die Zahl nur 100000 und nicht in Form von 100.000. Deine Kommentare zu diesem Test, den ich in diesem Post gemacht habe?