Datei laden und parsen (Optimierung)



  • Würde so etwas versuchen. So musst du den string nicht direkt überprüfen.

    void read_file( istream & str ) {
       int nr;
       double mreal = 0.0;
       double mimag = 0.0;
       double r;
    
       string line;
       while ( getline( str, line ) ) {
          stringstream sstr(line);
          int cou = 0;
          sstr >> nr;
          while ( sstr >> r ) {
             switch ( cou ) {
                case 0: mreal = r; break;
                case 1: mimag = r; break;
                default : 
                     cout << "error parsing '" << line << "'" << endl;
                     break;
             }
             cou++;
          }
          if ( cou ) {
             cout << "datensatz " << nr << ":" << mreal << "," << mimag << endl;
          }
          else {         
             cout << "neue Messreihe " << nr << endl;
          }
       }
    }
    

    Kurt



  • Fuer den ersten entwurf und um sein programm erstmal zum laufen zu bringen, voellig ok.
    Aber steckt auch noch bisserl optimierungspotential drinne .

    void read_file( istream & str ) {
       int nr;
       double mreal = 0.0;
       double mimag = 0.0;
       double r;
    
       string line; 
       while ( getline( str, line ) ) { // Die komplette Zeile wird kopiert, nach paarmal ist der string hoffentlich gross genug ^^
          stringstream sstr(line); // Der string wird gleich in nen object umgebaut, und dazu noch total neu konstruiert, sehr sicher, aber auch sehr rechenintensiv ^^ 
          int cou = 0;
          sstr >> nr; // tolle idee, die std streamoperationen gleich zu nutzen.
          while ( sstr >> r ) {
             switch ( cou ) {
                case 0: mreal = r; break;
                case 1: mimag = r; break;
                default :
                     cout << "error parsing '" << line << "'" << endl;
                     break;
             }
             cou++;
          }
          if ( cou ) {
             cout << "datensatz " << nr << ":" << mreal << "," << mimag << endl;
          }
          else {        
             cout << "neue Messreihe " << nr << endl;
          }
       }
    }
    

    Wie gesagt, fuer kleinere Sachen sicher akzeptabel, fuer zig millionen mal aufrufen sicher optimierungsbeduerftig ... und je nach implementation der STL wirst hier sehr unterschiedliche ergebnisse erzielen ....

    Punkte wo man ansetzen kann ...

    1. deine zeilen sind eigentlich definiert max lang, zumindest die Puffer (std::string) von haus aus gross genug Konstruieren ....

    2. bei der sofortigen kopie das neuerstellen des stringstreams verhindern, sondern in den puffer des alten schreiben lassen ... damit hilfst der STL nen new(aufn eigenen allokator zwar) zu vermeiden. Bei guten impls wirds nich viel ausmachen, weil die allokatoren recht flott sind

    Wenn das immer noch zu langsam ist, wirst dem mit reinen C++ mitteln kaum noch zu leibe ruecken koennen.
    Was die sache "langsam" macht, sind die X-maligen kopien ...

    eine variante, waere c++ klassen zu verwenden, die cow (copy on write) koennen (nicht mehr STL, dafuer unsicherer, code bleibt aber lesbar. faellt mir auf anhieb die MFC und die QT ein)
    oder auf selber in die hand nehmen und der sache mit C-Funktionen und roher pointerarithmetic auf die pelle ruecken.

    Ciao ...



  • Habs ein wenig optimiert. Jetzt wird nicht mehr so viel kopiert.

    void read_file( istream & str ) {
       int nr;
       double mreal = 0.0;
       double mimag = 0.0;
       double r;
    
       stringstream sstr;
       char buffer[100];
       while ( str.getline( buffer, 100 ) ) {
          sstr.str(buffer);
          int cou = 0;
          sstr >> nr;
          while ( sstr >> r ) {
             switch ( cou ) {
                case 0: mreal = r; break;
                case 1: mimag = r; break;
                default : 
                     cout << "error parsing '" << buffer << "'" << endl;
                     break;
             }
             cou++;
          }
          if ( cou ) {
             cout << "datensatz " << nr << ":" << mreal << "," << mimag << endl;
          }
          else {         
             cout << "neue Messreihe " << nr << endl;
          }
          sstr.clear();
       }
    }
    

    Mein erstes Posting sollte eigentlich nur die Idee zeigen dass man die überprüfung der Eingabezeile auch den streamfunktionen überlassen kann.
    Kurt



  • Jo er soll mal die standard ausgabe auskommentieren und laufen lassen ...
    wenns dann zufriedenstellend schnell durchlaeuft, hat er doch was er braucht ^^

    Ciao ...



  • DANKE DANKE DANKE DANKE.
    Da sind wirklich tolle Ideen dabei und ich habe jetzt auch eine Idee wie ich das Umsetzen kann.

    @RHBaum
    Wegen der Frage nach der Größenordnung: Im Moment ist das ganze noch off-line, also ist die Zeit noch relativ unkritisch. Es sollen aber später Messreihen mit 16k-Samples pro Sekunde gelesen werden.



  • Du bekommst dann deine daten nich mehr per file sondern per Stream ?
    oder per Net I/O ?

    nich das die geschichte mit dem File dann zum umweg wird ?

    glaub nich dass nen Messystem in ne datei reinstreamt und sich drauf verlaesst dass du konkurrierend zugreifend den muell selber da rausraeumst ^^

    also rein vom IO wenns sauber gemacht ist, iss 16kbyte / s eher unkritisch , da codier ich ja noch mp3's im hinnergrund bei ^^
    ich mach hier teilweisse mit 1000kbaud rum, ok, aber ich krieg meine daten auch per shared memory und mit events ... aber das parsen sollte da nich so das prob sein. In nen temp file schreiben schon eher, weil das zeitverhalten unter nichtechtzeit BS nicht definiert ist

    Ciao ...



  • Das wird dann später zweigleisig.
    Aktuelle Daten per Stream und da das Messsystem die Daten in Dateien ablegt benötige ich das Laden ja auch, um ältere Aufnahmen zu betrachten.



  • daishi schrieb:

    Das wird dann später zweigleisig.
    Aktuelle Daten per Stream und da das Messsystem die Daten in Dateien ablegt benötige ich das Laden ja auch, um ältere Aufnahmen zu betrachten.

    In dem Fall solltest du auf jeden Fall die Stream-Version verwenden (andernfalls benötigst du zwei gesonderte Funktionen für's einlesen vom Netzwerk (vermutlich über ein istream-Derivat) und Datei (FILE*).



  • Das system die daten in so Textformate als log wegspeichern is durchaus ueblich

    Das messysteme die daten in streams in der selben form irgendwo rausstreamen, iss eher unueblich ^^

    meist haben die systeme ne API (C-Header + dll) wo ma die daten pollen muss, oder noch besser per event benachrichtigt wird ...
    die daten liegen dann meist in schoenen C-Structs vor, andernfalls wuerd ich dem hersteller an die Gurgel springen ^^
    In dem Fall wuerd ich mir zur uebertragung nen format(protokoll) suchen(bauen) wo ich nimmer "parsen" muesst ^^

    Naja, ich kenn aber nich alles was es aufm Markt gibt, waer aber ziemlich ungewoehlich ....

    Ciao ...



  • hier mal trick 17 mit selbst überlistung:

    void read_file( istream & str ) {
       //zwischenspeicher
       float array[4];
       int index=0;
    
       while(str){
          str>>array[index];
          ++index;
          if(index==4){
              //test
              //wenn eine neue messreihe anfängt, hat das array folgende form:
              //messreihenNummer|0|zahl|0
              //es gibt keine messwertkonstellation, bei denen die beiden                      
              //nullen an genau diesen stellen auftauchen könnten.
              //wenn der erste wert keine messreihenNummer ist, so geht der     
              //datensatz von element 0-2. element 3 gibt dann entweder die
              //nummer einer neuen messreihe, oder den ersten wert eines 
              //neuen datensatzes an. Da messreihen laut dateischnipsel mit 1 beginnen, und datensätze mit einer 2, bleibt nur der offsetwert übrig.
    
              if(array[3]==0){
                   messreihenNummer=array[0];
                   data1=array[1];
                   data2=array[2];
                   data3=array[3];
    
                   //index zurücksetzen, array komplett ausgewertet
                   index=0;
              }
              else
              {
                   //kein offset wert.
                   //die ersten 3 daten bilden einen messwert
                   data1=array[0];
                   data2=array[1];
                   data3=array[2];
    
                   //der 4. wert wurde "zu früh" gelesen, und wird an den anfang gesetzt
                   array[0]=array[3];
    
                   //da der erste wert gültig ist, index nicht auf 0 sondern 1 setzen
                   index=1;
              }
          }
       }
    }
    

    //edit mom ich teste das eben schnell :p
    //edit2 der testschnipsel vom threadstarter funzt. Kriegts jemand noch schneller? jetzt wär ich mal so richtig gespannt^^


Anmelden zum Antworten