Rubrik: Variablen/Strings · String-Operationen | VB-Versionen: VB4, VB5, VB6 | 28.06.04 |
Stringverkettung optimiert Dieser "Klasse"-Tipp zeigt, wie sich das Anfügen von Text an einen bestehenden String um ein Vielfaches optimieren lässt. | ||
Autor: Roland Ortega | Bewertung: | Views: 17.134 |
ohne Homepage | System: Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | Beispielprojekt auf CD |
Zur Aufgabe / zum Problem:
Es soll eine Datenübertragung zwischen zwei PCs über das Winsock-Control realisiert werden (identische Verhältnisse hat man bspw. auch beim asynchronen Download per Inet-Control, wenn man z.B. eine eigene Fortschrittsanzeige haben möchte). Das Problem dabei ist, dass die Daten "portionsweise" eintreffen und auf dem Zielrechner erst wieder zusammengesetzt werden müssen.
Natürlich geht das in VB ganz einfach:
Gesamtstring = Gesamtstring & Datenpaket
Bei etwas grösseren String, so im MB Bereich, dauerte das Ganze aber schier "unendlich" lange, so dass trotz eines 100 MBit lokalen Netzwerks kaum mehr ISDN Geschwindigkeit herauskommt.
Um die Stringverkettung zu optimieren, war der erste Gedanke: RTLMoveMemory-Funktion aus dem Windows API. Doch dann bin ich auf eine recht simple und mit reinen VB-Mitteln realisierbare Variante gestossen, die bei grossen Strings locker um den Faktor 1000 und mehr schneller ist.
Herausgekommen ist folgendes Klassenmodul:
Option Explicit ' private Variablen Private sCollect As String Private nLen As Long Private sTemp As String
Private Sub Class_Initialize() ' Sammelstring vor-initialisieren Reset End Sub
Public Sub Reset() sCollect = String$(100, " ") nLen = 0 End Sub
Public Property Get Result() As String ' korrekter Rückgabe-String Result = Left$(sCollect, nLen) End Property
Public Sub Add(sString As String) If Len(sString) + nLen > Len(sCollect) Then ' Es ist wichtig für die Performance, dass der String ' immer verdoppelt wird, da ansonsten zu oft ' neuer Speicherplatz angefordert würde, was die ' Performance wiederrum zunichte macht sTemp = Left$(sCollect, nLen) sCollect = String$(2 * Len(sCollect) + Len(sString), " ") Mid$(sCollect, 1, nLen) = sTemp sTemp = "" ' damit der Speicher wieder frei wird ! End If Mid$(sCollect, nLen + 1, Len(sString)) = sString nLen = nLen + Len(sString) End Sub
Das Prinzip:
Bevor dem bestehenden String der neue String angefügt wird, wird der bestehende String bei Bedarf "verdoppelt", d.h. mit entsprechend Leerzeichen aufgefüllt, so dass sich die Stringlänge verdoppelt. Grund ist der, dass bei häugigen String-Anfügefunktionen nicht jedes Mal neuer Speicherplatz vom System angefordert werden muss! Der neue String wird dann einfach in den bestehenden (zu langen) String an der korrekten Position "eingefügt".
Ein kleines Beispielprojekt:
Starten Sie die VB-Entwicklungsumgebung und fügen dem Projekt ein neues Klassenmodul mit obigen Code hinzu. Platzieren Sie auf die Form1 zwei CommandButtons (Command1 und Command2). Beim Klick auf die CommandButtons soll 10000 mal das Alphabet (String mit 26 Buchstaben) zu einem bestehenden String hinzugefügt werden.
Option Explicit Dim sAlphabet As String
Private Sub Form_Load() Dim i As Long sAlphabet = "" For i = 65 To 90 sAlphabet = sAlphabet & Chr$(i) Next End Sub
Private Sub Command1_Click() Dim nTime As Single Dim sResult As String Dim i As Long nTime = Timer ' ------------------------------------------------------------ ' Simpel: Die Aufgabe lösen, indem an den späteren Zielstring ' immer wieder der gewünschte String angehängt wird ... For i = 1 To 10000 sResult = sResult & sAlphabet Next i MsgBox "Benötigte Zeit: " & _ Format$(Int((Timer - nTime) * 1000), "#,###,##0 ms") End Sub
Private Sub Command2_Click() Dim nTime As Single Dim sResult As String Dim i As Long nTime = Timer ' ------------------------------------------------------------ ' die bessere Variante: Erst den Speicherplatz reservieren ' und dann gezielt den String einbauen Dim oClass As New Class1 For i = 1 To 10000 oClass.Add sAlphabet Next i MsgBox "Benötigte Zeit: " & _ Format$(Int((Timer - nTime) * 1000), "#,###,##0 ms") End Sub
Das Ergebnis:
Die erste Variante (VB-Standard-Stringverkettung) benötigte im Test 843 ms. Die zweite Variante, bei der der String über das Klassenmodul zusammengesetzt wurde, benötigte für das gleiche Resultat nur 14 ms!
Es kommt aber noch dicker: Verdoppeln Sie einmal den Durchlaufwert von 10000 auf 20000. Hier braucht die erste Variante dann schon sage und schreibe 16034 ms. Die zweite Variante hingegen erledigte die gleiche Aufgabe in hervorragenden 31 ms!!!