Interessanter Benchmark: Veränderbare Zeichenfolge vergleichen



  • Schreibe gerade einen Parser, der mir die Werte einer HTML-Tabelle parst (damit man sie dann z. B. in einer SQL-Datenbank speichern kann). Es soll direkt vom URL-Stream gelesen werden können (ohne die HTML-Datei zwischenzuspeichern, also ohne die Möglichkeit zurück zu positionieren). Aus diesem Grund muss ich beim scannen Zeichen zwischenspeichern. Dafür habe ich einen StringBuilder vorgesehen, da ja bei jedem gelesenen Zeichen eines angefügt werden muss. Nicht ideal mit normalen C#-strings, die ja leider nur Read Only sind.

    Leider habe ich festgestellt, dass es anscheinend keine Möglichkeit gibt, Stringbuilder (den Inhalt) zu vergleichen (nutze aber VS 2005, ist das in neueren Versionen evtl. möglich?) und habe daher mal ein kurzes Benchmarkprogramm erstellt, um die Effizienz zwischen einem Character-Array und einem StringBuilder beim Vergleichen zu vergleichen (geiler Satz ;-).

    Die einzige Möglichkeit, die ich beim StringBuilder sehe ist die Methode "ToString()", die aber jedes mal den kompletten String zurückgibt (Rückgabe geht doch normalerweise über den Stack? Problematisch). Bei meiner Array-Lösung vergleiche ich dagegen die einzelnen Zeichen direkt. Der Benchmark ist interessant. Sind beide Strings gleich, sind beide Versionen ungefähr gleichschnell. Unterscheidet sich das erste Zeichen ist die händische Version mit dem char-Array um fast Faktor 10 schneller.

    Gibt es wirklich keine Methode um den Inhalt von StringBuildern (idealerweise mit Bereichsangabe) direkt zu vergleichen. Es geht mir nicht mal so um die Geschwindigkeit. Aber ToString() gibt ja jedes mal einen String zurück (die Zeichenfolge wird kopiert), wodurch der Garbage Collector viel Arbeit bekommt (in meiner Anwendung wird er immer nur zum Vergleichen benötigt und danach ist er Garbage).

    So hier das Benchmark-Programm, ich denke ihr bekommt es hin, das so zu ändern, die eine oder andere Variante zu testen:

    // Benchmarktest für Vergleichen von 2 änderbaren Zeichenfolgen
    // Ändert man das "h" von sb2 zu "H" (beide Strings gleich)
    // sind beide Versionen ungefähr gleich schnell. Ist das
    // erste Zeichen schon falsch (wie in diesem Beispiel), ist
    // die ´"umständliche" (händische) Methode um fast den
    // Faktor 10 schneller(!).
    // 
    // WICHTIG: Man muss bei sb2 und a1 das "h" zu "H" ändern, mit
    // "h" ist die "sb-Version um ca. 1 Sekunde schneller, die 
    // "a-Version" fast um den Faktor 10 (2,xxx statt 18,xxx) schneller
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace testCon {
    
    class Program {
        static void Main(string[] args) {
            StringBuilder sb=new StringBuilder(256);
            StringBuilder sb2=new StringBuilder(128);
            //string s;
            sb.Append("Hello, world");
            sb2.Append("hello, world");
            char[] a={'H','e','l','l','o',',',' ','w','o','r','l','d'};
            char[] a1={'h','e','l','l','o',',',' ','w','o','r','l','d'};
            int i;
            int match=0;
            DateTime start=new DateTime();
            DateTime stop=new DateTime();
            start=DateTime.Now;
            for (int loop=1; loop <10; loop++) {
                for (i=0; i < 20000000; i++) {
                    //if (sb.ToString() == sb2.ToString())
                    //    match++;
                    ///* WAHLWEISE VON BEIDEN OBIGEN ZEILEN KOMMENTAR ENTFERNEN UND VON DIESEM
                    //   Kommentarblock die "//" vor den Kommentarblockzeichen /* und * / löschen
                    int length=sb.Length;
                    for (int j=0; j < length; j++) {
                        if (a[j] != a1[j])
                            goto NO_MATCH;
                    }
                    match++;
        NO_MATCH:
                    //*/ // HIER ENDE DES KOMMENTARBLOCKS
                    continue;
                }
            } // for (int loop=1; ...)
            stop=DateTime.Now;
            TimeSpan diff=stop-start;
            Console.WriteLine("{0} matches\n",match);
            Console.WriteLine("Zeit: {0}\n",diff);
        }
    
        public void func() {
        }
    } // class Program
    
    } // namesp8ace testCon
    


  • Dir ist schon klar, dass du dabei bist den Inhalt selbst in dem StringBuilder zwischenspeichern? Dann kannst du ihn auch direkt woanders zwischenspeichern. 🙄

    Wenn die HTML-Seite valides XHTML ist, kann du auch versuchen auch einen XMLReader zu verwenden.

    > Und wo wir schonmal dabei sind goto ist böse. Ich habe selbst in komplizierten Fällen auf goto verzeichtet.



  • Rhombicosidodecahedron schrieb:

    Dir ist schon klar, dass du dabei bist den Inhalt selbst in dem StringBuilder zwischenspeichern? Dann kannst du ihn auch direkt woanders zwischenspeichern. 🙄

    Nee, ist mir ehrlich nicht klar was Du meinst (ich lerne C# erst noch)

    Rhombicosidodecahedron schrieb:

    Wenn die HTML-Seite valides XHTML ist, kann du auch versuchen auch einen XMLReader zu verwenden.

    Was bedeutet "valides XHTML"? Es ist diese Seite:

    DAX, Börse Frankfurt. Mein Parser ist mittlerweile so weit, dass er die Tabelle gefunden hat und jetzt direkt nach dem ersten Zeilen-Tag (<tr ...> steht, ab der die Kurse kommen. Jetzt muss ich halt noch für jede Zeile den Inhalt der Zellen auslesen (allerdings sind in jeder Zeile noch etliche Formatierungs-Tags, die man überspringen muss). Wenn es da irgend etwas in .Net gibt, dass mir das automatisiert, wäre ich natürlich heilfroh. Aber bislang konnte ich in meinen Büchern (und ich habe da 3 Stück, zwei von Microsoft Press) nichts finden.

    > Und wo wir schonmal dabei sind goto ist böse. Ich habe selbst in komplizierten Fällen auf goto verzeichtet.[/quote]

    Aber jetzt bitte nicht mit dem Korinthen-Kacken anfangen. Das ist ein Test-Programm gewesen, mit dem ich die Effizienz verschiedener Lösungswege vorab testen wollte. Da war halt mal das goto die mit Abstand schnellste Lösung.



  • johan schrieb:

    Aber bislang konnte ich in meinen Büchern (und ich habe da 3 Stück, zwei von Microsoft Press) nichts finden.

    Es gibt da eine neue, hochmoderne Technologie. Nennt sich: Internet! Da kannst Du nach Informationen suchen und bekommst diese quasi umsonst frei haus:

    http://lmgtfy.com/?q=Html+C%23+parsen

    Und schon der dritte Link gibt umfangreiche Informationen wie man es richtig macht:

    http://olussier.net/2010/03/30/easily-parse-html-documents-in-csharp/

    [/quote]

    johan schrieb:

    Aber jetzt bitte nicht mit dem Korinthen-Kacken anfangen. Das ist ein Test-Programm gewesen, mit dem ich die Effizienz verschiedener Lösungswege vorab testen wollte. Da war halt mal das goto die mit Abstand schnellste Lösung.

    Die Tatsache das Du in dem Kontext überhaupt an goto denkst ist bereits bedenklich. Und die Erfahrung zeigt das man solche schlechten Angewohnheiten später nur schwer wieder ablegt. Daher: Wehret den Anfängen.



  • Versuchst du Intraday-Kursserien zu sammeln, indem du einschlägige Websites parst? 🙂

    Oder nur Endofday?



  • int length=sb.Length;
                    for (int j=0; j < length; j++) {
                        if (a[j] != a1[j])
                            goto NO_MATCH;
                    }
                    match++;
        NO_MATCH:
    

    Etwas derartiges mache ich meist so:

    int length=sb.Length;
    bool NotEqualFlag = false;
    for (int j=0; j < length; j++) 
    {
       if (a[j] != a1[j])
       {
          NotEqualFlag = true;
          break; 
       }
    }
    
    if ( !NotEqualFlag )
        Match++;
    

    ich habe noch nie einen guten Grund gefunden, GOTO zu verwenden. Es gibt eigentlich immer sauberere und übersichtlichere Lösungen. Auch in noch so gammeligen und provisorischen Testprogrammen kann man getrost auf GOTO verzichten.


Anmelden zum Antworten