Einzelnen Beitrag anzeigen

SearchBot

Registriert seit: 27. Jun 2004
Ort: N-W vom Bodensee
232 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#7

AW: String kopieren, was ist schneller?

  Alt 8. Jan 2015, 18:47
Hallo und danke für Euer Interesse

Für alle: Riesenstring ist eine XML-Datei, genaugenommen eine Tabelle mit rund 10000 Zeilen und 572 Spalten - aus der ich nur 3 Spalten benötige...

Wahrscheinlich schieße ich mir sowieso von hinten durch die Brust ins Auge, oder so.
Aktuell ist aber dies die schnellste Lösung für mein Projekt und ich habe die letzte 4 Wochen schon allerlei probiert...

Ich habe es auch schon mit XML-Nodes und so versucht, aber verworfen, weil es zu lange Verarbeitungszeiten gibt. Wahrscheinlich habe ich auch was falsch gemacht - ist aber jetzt nicht das Thema
Daher ist mir der String-Überflieger lieber.

Eine Kopie des RiesenString kann ich im erzeugten Code auch nicht finden.

Du verwendest doch hoffentlich das PosEx aus AnsiStrings und nicht das aus StrUtils?

Warum nutzt du eigentlich nicht den dritten Parameter von PosEx für die Startposition der Suche?
Die Kopie wird offenbar vom Copy-Befehl erzeugt. Ich beobachte dazu den freien Speicher vor und nach dem Befehl, um das festzustellen

Genaugenommen verwende ich das PosEx aus der optimierten FastCode-Unit. Dieser ist in Assembler geschrieben und verwendet AnsiStrings(..wobei mir jetzt gerade auffällt, daß ich die Unit AnsiStrings noch garnicht kenne?!).

Den dritten Parameter hatte ich vergessen, als ich meinen Post fern von meinem Delphi an einem anderen PC eingetippt habe. Den versuche ich auch gerade zu verwenden, um mich portionsweise durch den Riesenstring zu schieben, klappt aber grad noch nicht so wie gewünscht (ein müdes Hirn macht mehr Denkfehler )...

1) Warum werden überhaupt die Marker im String gesetzt?
Wenn die Position einmal ermittelt wurde, kann der Teilstring doch sofort verarbeitet werden.
2) Warum wird zur Weiterverarbeitung eine Kopie gemacht?
3) Benötigt wird doch nur ein Pointer(PAnsiChar) auf das erste Zeichen und die Anzahl der zu verarbeitenden Zeichen.

4) Bei solch großen Dateien bietet es sich an mit Memory Mapped Files (MMF) zu arbeiten.
1) Weil das am schnellsten geht und zeitgleich den Riesenstring etwas verkleint (StringReplace). Im kurzen Teilstring kann ich sie dann meine 3 Zielfelder direkt finden und rauskopieren. Dachte mir, daß das schnellergeht, als wenn ich immer den Riesenstring durchs Copy laufen lasse. Zumal ich nach dem ersten Durchlauf noch 10000 weitere Zeilen vor mir habe...

2) Eine Kopie macht offenbar der Befehl copy, wenn ich mit dem Taskmanager den "Verwendungsverlauf des physikalischen Speichers" beobachte. Daher suche ich ja eine Alternative zu Copy, wenn es geht.

3) Aah, mit Pointern hab ichs nicht so... Die Positionen bekomme ich ja leicht raus, aber es geht ja um das zeitaufwändige rauskopieren...

4) Ursprünglich bekomme ich die Datei als MemoryStream. Dann schiebe ich das geschwind in einen StringStream, dessen DataString ich dann in meinen Riesenstring (der schlicht s heißt, aber des Verständnisses wegen ich so ausführlich benenne) setze, um die Bearbeitungen durchzuführen.
MMF ist für mich jetzt ein neues Stichwort, danke schön

Den Teilstring muss man auch nicht kopieren. Wenn ich weiß, wo der anfängt, und wie lang er ist (1800 Zeichen), kann ich alle weiteren Operationen mit dieser Information machen. Und zuerst Marker zu verteilen, die man hinterher eh wieder rauslöscht, ist vielleicht auch nicht das Gelbe vom Ei.

Anhand welcher Kriterien werden die Marker denn gesetzt?
Im Grunde weiß ich nicht genau, ob er immer so lang ist. Daher setze ich die Marker, um für meinen dritten Wert die Endposition in der aktuellen Zeile zu finden.
Wie am Anfang beschrieben suche ich bestimmte Spalten. Jede Zielspalte bekommt einen anderen Marker, um diese Werte dann schnell wieder zu finden.
Eigentlich lösche ich nur den "Zeilen-Ende"-Marker, weil das mit dem PosEx-Offset noch nicht so klappt. Daran will ich nachher weiter basteln
Mit der Fastcode-StringReplace-Funktion, die ich zu diesem Zweck etwas umgebaut habe, werden die 150MB in gefühlten 2 Sekunden an den 10000 Stellen markiert, was ich 3x mache (also rund 6 Sekunden Vorbereitungszeit - das ist ok, finde ich).

1) Warum willst du die Datenquelle überhaupt ändern (Marker setzen)?
2) Es reicht doch vollkommen die Position im Text zu kennen und die Länge, dann kann man mit diesen Informationen sehr hübsch sich den Teilstring aus der Datenquelle holen.
1) Die Datenquelle wird nicht verändert, ich arbeite ja mit einer Kopie. Und die zerschnibble ich, was ich eben daraus brauche

2) genau. Und das Rausholen des Teilstrings möchte ich beschleunigen, schneller als der Befehl Copy, wenn das geht - und das geht bestimmt irgendwie...

Die Zeiger&Länge Lösung erscheint mir sinnvoll, besonders wenn du wiederholt auf die Teilstrings zugreifen musst. Damit baust du dir praktisch einen Index auf dem Hauptstring.

Wenn du nur einmal darauf zugreifen musst, kannst du den Teilstring auch wirklich gleich verarbeiten (#3).
Ja, sobald er schnellst möglich aus dem Riesenstring separiert ist.

Vielleicht möchtet ihr die umgebaute FastCode-StringReplace noch sehen?
Original: AnsiStringReplaceJOHIA32Unit3.pas
Ich habe sie dahingegend erweitert, daß nach jedem Fund und Replace ein anderer String gesucht wird - in diesem Fall mittels eine Zahl; also sozusagen ein StringReplace mit Counter. Passend, weil jedes Tabellenfeld zB A99, A100, A101... heißt. Das macht die ursprüngliche Routine etwas langsamer, aber ist im Vergleich immernoch superschnell
Angehängte Dateien
Dateityp: pas FastStrings.pas (19,6 KB, 11x aufgerufen)
  Mit Zitat antworten Zitat