Echt lange Strings bauen

Das dynamische Erzeugen von Strings um z.B. SQL-Statements oder Zeilen für Datenexporte zu bauen geht mit Gupta eigentlich recht flott – zumindest wenn die resultierenden Strings weit unter 1.000.000 Zeichen lang sind. Der Bedarf für dynamisch zusammengesetzte Strings jenseits der 32kByte-Grenze ist ja auch gering: SQL-Statements sind i.d.R. auf 32 kByte Länge begrenzt, da sonst der Input-Buffer meckert. Die Multiline-Textbox ist auf diese Länge begrenzt. Bei zeilenorientierten Exporten hat man selten mit extrem langen Datenzeilen zu tun.

Konkatenieren kann dauern

Beim Serialisieren von Daten z.B. im XML- oder JSON-Format kann es aber vorkommen, dass man sehr lange Strings mit über 1-10 MByte erzeugen muss, ohne sie zwischendurch auf die Festplatte wegschreiben zu können. Dabei wird jeweils ein kurzer String (z.B. ein XML-Tag mit Inhalt und Abschlusstag) an den Output-String angehängt. Ab einer bestimmten Länge wird der Zeitbedarf jedoch extrem. Bis zur Größe von 500.000 Zeichen dauert das auf einem normalen Desktop-Rechner etwa zwei Sekunden. Eine Million Zeichen dauern schon bis zu 40 Sekunden. Bei zehn Millionen Zeichen hatte ich keine Geduld mehr. Das musste optimiert werden. Denn an sich hat Gupta kein Problem mit sehr großen Strings: Files mit einer Größe von zig Megabyte kann man mit SalFileRead(…) ohne weiteres als BLOB einlesen. Zeitraubend ist das häufige Anfügen kurzer Strings an einen sehr langen.

Analyse

Für eine quantitative Analyse habe ich ein kleines Programm geschrieben, das in einer Schleife einen kurzen String mit einer Länge von 10 Zeichen an den String sOut anfügt. Einmal pro 100 Durchläufe wird die Zeit gemessen und in eine CSV-Datei exportiert. Heraus kommt folgendes Diagramm:

StringAppend Time Length Diagram

Man sieht einen scharfen Knick bei einer Stringlänge von 500.000 Zeichen ab dem das Anfügen weiterer Stringparts wesentlich länger dauert  (im Debug-Mode beginnt der Knick übrigens schon bei 100.000 Zeichen).

String-Beschleuniger

Fügt man die Stringparts nicht direkt dem Output-String an, sondern an einen „Zwischenstring“, der erst ab einer bestimmten Länge N dem Output-String angefügt wird, kann man den Vorgang insgesamt beschleunigen. Den optimalen Wert für N habe ich durch eine Testreihe ermittelt. Er liegt zwischen 10.000 und 20.000, wie man in der folgenden Grafik sieht. Es dauert dann nur noch ca. 13 Sekunden, bis ein 10 MByte großer String aus insgesamt einer Million String-Anfügungen zusammengebaut ist.

StringBuilder Performance Run

StringBuilder Performance Run

StringBuilder

Das oben beschriebene Verhalten habe ich in eine Klasse StringBuilder gepackt: Deren Methoden Append(…) fügt Teilstrings an, mit ToString() holt man den fertigen String ab. Lenght() liefert die aktuelle Länge des Gesamtstrings und Clear() setzt ihn zurück. Den Programmcode des StringBuilders inklusive der Performance-Tests könnt ihr herunterladen.

Download

StringBuilderPerfomanceTests.zip

Happy coding

Advertisements

Über thomasuttendorfer
Ich bin Entwicklungsleiter bei der Softwarefirma [ frevel & fey ] in München. Wir entwickeln Business-Software für Verlage und verwenden dafür den Gupta Team-Developer sowie Visual Studio.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: