Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Die Performancefalle ReDim Preserve

Geschrieben von: Christoph Wille
Kategorie: VB.NET

This printed page brought to you by AlphaSierraPapa

Wer mit Arrays in VB arbeitet, dem wird auch das ReDim Statement zum Verändern der Größe eines Arrays nicht unbekannt sein. Heute werde ich Ihnen ausführlich darlegen, warum Sie dieses Statement in Zukunft besser nicht mehr, oder nur noch sehr, sehr selten einsetzen sollten.

Die Einsatzmöglichkeiten von ReDim

Bevor ich jetzt über das ReDim Statement herfalle und es zerzause, möchte ich noch einmal die üblichsten Anwendungsfälle anhand eines Codebeispiels zeigen (redimsamples.aspx). Dabei handelt es sich um das simple ReDim, als auch ReDim Preserve:

<% @Page Language="VB" %>
<%
Dim arrStrings(1) as String
Response.Write(UBound(arrStrings) & "<br>")

ReDim arrStrings(20)
Response.Write(UBound(arrStrings) & "<br>")

ReDim Preserve arrStrings(25)
Response.Write(UBound(arrStrings) & "<br>")
%>

ReDim erlaubt es, ein Array zu vergrößern oder zu verkleinern. Dabei wird immer ein neues Array angelegt. Der Grund hierfür ist, daß das VB.NET Array vom System.Array der .NET Runtime hergeleitet ist, und dieses per Definition eine ab Ersterstellung fixe Größe hat. In C# ist das offensichtlich, wie der folgende Code - der ReDim emuliert - zeigt:

string[] arrTest = new string[1];
// und jetzt wollen wir die Größe verändern: ReDim arrTest(20)
arrTest = new string[20];

An sich ist das kein Problem, das Problem kommt erst mit Preserve (unser heutiges Thema). Wenn man Redim mit dem Schlüsselwort Preserve verwendet, so werden die alten Elemente beibehalten - als Kopie im neuen Array.

ReDim Preserve als Performancekiller

Im Prinzip ist die Katze bereits aus dem Sack - das ReDim Preserve Statement erzeugt ein neues Array - und die Elemente des alten Arrays werden in das neue kopiert. Da dies unter VB.NET (wie auch im "alten" VB) implizit passiert, merkt man außer schlechter Performance nichts. Um es etwas krasser zu zeigen, habe ich einen Loop gebastelt, der ein Array fünftausend Mal ReDimmed (redimloop.aspx).

<% @Page Language="VB" Trace="True" %>
<%
Dim arrStrings() as String
Dim i as Integer

Trace.Write("Redim","Start")

For i = 1 To 5000
  ReDim Preserve arrStrings(i)
  arrStrings(i-1) = i
Next

Trace.Write("Redim","End")
%>

Da ich Tracing eingeschaltet habe, kann ich sehr einfach die Performancedaten ermitteln:

Natürlich wird das mit jedem Aufruf etwas differieren (und mit der Maschine), aber man bekommt einen groben Anhaltspunkt für die Performance - und es zählt ja die Relativperformance auf ein und derselben Maschine.

Was passiert aber im Hintergrund, wenn man ReDim Preserve aufruft? Um es zu illustrieren, habe ich das ReDim Statement in C# nachgebaut - weil dort muß man alles händisch machen, was ReDim in VB.NET automatisch hinter den Kulissen veranstaltet (redimloopexplicit.aspx).

<% @Page Language="C#" Trace="True" %>
<%
string[] arrStrings = new string[1];
int i;

Trace.Write("Redim","Start");

for (i=1;i<=5000;i++)
{
  string[] arrHelper = new string[i];
  arrStrings.CopyTo(arrHelper, 0);
  arrHelper[i-1] = i.ToString();
  arrStrings = arrHelper;
}

Trace.Write("Redim","End");
%>

Hier sieht man deutlich, wie schlecht die Performance sein muß - zuerst wird ein Array der neuen Größe angelegt, und dann der Inhalt des alten Arrays in das neue kopiert. Die Laufvariable wird zugewiesen, wobei ich in C# den Cast zu String selbst machen muß. Und zu guter letzt wechsle ich die Arrayvariablen aus.

Wer glaubt, VB.NET macht was anderes, der irrt - die Performance ist haarklein dieselbe wie ReDim Preserve (mein Code ist vielleicht eine Spur besser, weil ich das Verkleinern des Arrays nicht berücksichtige). Wie schlecht die Performance tatsächlich ist, sieht man allerdings erst im Vergleich mit einer besseren Technologie - der ArrayList Klasse.

Die beste Lösung - ArrayLists

Die beste Lösung für ein dynamisches Array ist die ArrayList Klasse aus dem System.Collections Namespace. Eine ArrayList kann dynamisch wachsen und schrumpfen, und ist in der Verwendung äußerst einfach (arraylistloop.aspx):

<% @Page Language="VB" Trace="True" %>
<% @Import Namespace="System.Collections" %>
<%
Dim arrList as New ArrayList(100)
Dim i as Long

Trace.Write("ArrayList","Start")

For i = 1 To 50000
  arrList.Add(i)
Next

Trace.Write("ArrayList","End")
%>

Wer genauer hinsieht wird bemerkt haben, daß der Loop nicht bis fünftausend, sondern bis fünfzigtausend läuft - der Grund: mit fünftausend konnte ich die Performance nicht messen. Aber mit fünfzigtausend ist sie immer noch sehr beeindruckend:

Die Ausführungszeit ist 0.01 zu 0.45 - und das obwohl der Loop zehn Mal öfters läuft! Ich wollte ReDim Preserve ebenfalls mit dieser Anzahl laufen lassen, habe aber dann irgendwann den Server resetted...

Schlußbemerkung

Die Quintessenz des Artikels ist daß man unter VB.NET dringend die Finger von ReDim Preserve lassen sollte. Wenn man veränderbare Arrays braucht, sollte man statt dessen zur ArrayList greifen, die sich sowieso fast wie ein normales Array verhält.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20001025.zip

Verwandte Artikel

Verwendung von Arrays in C#
http:/www.aspheute.com/artikel/20000731.htm
Wetterbericht per SMS versenden
http:/www.aspheute.com/artikel/20010913.htm

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.