![]() |
String kopieren, was ist schneller?
Hallo,
ich suche eine Optimierung. Folgendes Projekt habe ich da: 150MB String, genaugenommen rund 10000 Zeilen mit je ca. 18kB Zeilenlänge, von denen ich aber nur rund 1800 Zeichen brauche, und von denen auch nur 30 Zeichen pro Zeile :stupid: Mit den optimierten (und leicht umgebauten) Fastcode-Challenge-Routinen von StringReplace :thumb: setze ich mir in wenigen Sekunden rund 30000 Marker im String, nach diesen Markern steht die Info, die ich brauche.
Delphi-Quellcode:
Das Copy braucht ne Weile und 150MB extra (offenbar für eine Arbeitskopie des Strings).
var TeilString, Riesenstring: AnsiString; p:integer;
//Marker ist ein einzelnes Char, zB #9 p:=PosEx(Marker,RiesenString); repeat Teilstring:=copy(Riesenstring,p,1800); RiesenString[p]:=#32; //löschen des Markers p:=PosEx(Marker,RiesenString); //..Mache was mit dem Teilstring.. (3x weitere copy mit anderen Markern) until p=0; Gibt es was schnelleres als Copy? CopyBlock vielleicht? Gerne auch ohne, daß nochmal 150MB im Speicher benötigt werden, weshalb ich auch auf gleiche Stringtypen achte, damit hoffentlich keine zeitaufwändige Konvertierung im Hintergrund nötig ist. Derzeit benötigt meine Routine rund 50s für 100 Zeilen... :pale: Danke schonmal fürs mitdenken :wink: |
AW: String kopieren, was ist schneller?
Ich habe jetzt gerade kein XE verfügbar, aber unter XE2 entspricht das Copy im Wesentlichen einem Move-Befehl. 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? Wie es jetzt ist, beginnt die Suche immer am Anfang des RiesenString. Deshalb musst du auch den Marker ausblenden. Abgesehen davon ist das von der Performance her eher ungünstig. So wäre es deutlich geschickter:
Delphi-Quellcode:
p:=PosEx(Marker,RiesenString, 1);
repeat Teilstring:=copy(Riesenstring,p,1800); // Annahme: der nächste Marker kann erst nach dem Teilstring kommen p:=PosEx(Marker,RiesenString, p + 1800); //..Mache was mit dem Teilstring.. (3x weitere copy mit anderen Markern) until p=0; |
AW: String kopieren, was ist schneller?
Warum werden überhaupt die Marker im String gesetzt?
Wenn die Position einmal ermittelt wurde, kann der Teilstring doch sofort verarbeitet werden. Warum wird zur Weiterverarbeitung eine Kopie gemacht? Benötigt wird doch nur ein Pointer(PAnsiChar) auf das erste Zeichen und die Anzahl der zu verarbeitenden Zeichen. Bei solch großen Dateien bietet es sich an mit Memory Mapped Files (MMF) zu arbeiten. |
AW: String kopieren, was ist schneller?
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? |
AW: String kopieren, was ist schneller?
Eventuell muss man auch mal etwas anders denken.
Warum willst du die Datenquelle überhaupt ändern (Marker setzen)? Das sind Meta-Informationen, die du zur Verarbeitung benötigst und die haben in der Datenquelle nichts zu suchen. 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. |
AW: String kopieren, was ist schneller?
Frei nach Wheeler: Jedes Problem in der Informatik kann durch eine weitere Indirektionsstufe gelöst werden :mrgreen:
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). |
AW: String kopieren, was ist schneller?
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo und danke für Euer Interesse :-D
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. :roll: 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 :wink: Daher ist mir der String-Überflieger lieber. Zitat:
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 :oops: )... Zitat:
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 :idea: Zitat:
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 :wink: 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). Zitat:
2) genau. Und das Rausholen des Teilstrings möchte ich beschleunigen, schneller als der Befehl Copy, wenn das geht - und das geht bestimmt irgendwie... Zitat:
Vielleicht möchtet ihr die umgebaute FastCode-StringReplace noch sehen? Original: ![]() 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 :stupid: |
AW: String kopieren, was ist schneller?
Zitat:
Also schreibe dort keinen Merkel rein, sondern merke dir die Position und die Länge. Wenn du die Daten dann brauchst, dann einfach ab der Position in der Länge die Daten aus dieser Datenquelle herausnehmen. |
AW: String kopieren, was ist schneller?
Zitat:
![]() |
AW: String kopieren, was ist schneller?
hmm warum "saust" du nicht einfach mit 2 PChars da durch.
Wenn Du an der richtigen Stelle bist von PCharDest := PCharSource bis du aus dem Bereich bist.. sonst immer nur nette inc's des PChars... nix ist schneller... Oder habe ich da was falsch verstenden? |
AW: String kopieren, was ist schneller?
Zitat:
Er saust da nur über das Ziel hinaus. Erst in alle Ecken pinkeln, und dann mit der Nase am Boden die Stellen suchen, die nach Laterne unten riechen, die Stelle wischen und dann endlich dort etwas machen. Hört sich nicht nur umständlich an, ist es auch. |
AW: String kopieren, was ist schneller?
Zitat:
|
AW: String kopieren, was ist schneller?
Der Ansatz ist wirklich durch die Brust ins Auge und dann ins Knie... Du hast ja mehrere Suchvorgänge, wo doch ein einzelner genügt.
- Du hast eine Routine, die den Startmarker setzt - Du hast eine Routine, die den Endmarker setzt Statt den String zu modifizieren, läßt du dir die Position im String jeweils zurückgeben. Das Stück kopierst du heraus und verarbeitest es weiter.
Delphi-Quellcode:
BTW... Wenn du den MemoryStream in einen StringStream uschaufelst, wird dann nicht noch eine Kopie erzeugt ? ;)
...
sp:=GetStartPosition(RiesenString); ep:=GetEndPosition(RiesenString, sp); //Sucht ab sp nach dem Ende VielKleinererString:=copy(RiesenString, sp, ep); //Weiterverarbeiten des VielKleinererString |
AW: String kopieren, was ist schneller?
Zitat:
Also gut, ok, :oops: die Positionierung kann ich also noch besser machen - aber wie ist das jetzt mit dem rauskopieren meiner Werte, nachdem ich also die Positionen gefunden habe? Gibt's da was schnelleres als copy und wie müsste das dann aussehen? |
AW: String kopieren, was ist schneller?
Ähm, du reist von Bremen über Paris, Rom, Madrid nach Hamburg, aber der Weg zur Kneipe um die Ecke ist dir zu weit?
Stell das um, nimm das Copy und schau dir die Zeiten an. Den größten Teil verbrätst du beim Suchen, Suchen |
AW: String kopieren, was ist schneller?
Ist move für Buffer nicht eine Alternative zu copy?
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:11 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz