2014-11-23 14 views
5

Ich verwende Delphi RAD Studio XE2. Ich habe kürzlich mit Dateiströmen herumgespielt und einige interessante Ergebnisse gefunden, die mich zu dieser Frage geführt haben.Datei-Streaming in Delphi - Optimale Puffergröße

Was ist die optimale Puffergröße für eine TStreamReader in Delphi? Zum Beispiel lade ich eine 1-GB-Datei mit 2 Millionen Zeilen im Format doubleTABdoubleTABdouble. Wenn ich es in eine TStringList mit dem folgenden Code laden, bekomme ich dramatisch unterschiedliche Ergebnisse für verschiedene Puffergrößen. Mit Ergebnissen meine ich Verarbeitungsgeschwindigkeit und RAM-Auslastung.

reader := TStreamReader.Create(fileLocation, TEncoding.UTF8, True, NumBytes); 
try 
    stringList.BeginUpdate; 
    try 
    stringList.Clear; 
    while not reader.EndOfStream do 
     stringList.Add(reader.ReadLine); 
    finally 
     stringList.EndUpdate; 
    end; 
    finally 
    reader.Free; 
    end; 
end; 

Die optimale Puffergröße scheint zwischen 1024 und 4096. zu sein, wenn es als 1024 weniger eingestellt ist es scheint linear zu verlangsamen und scheint mehr RAM zu verwenden. Wenn es über 4096 gesetzt wird, scheint es exponentiell zu verlangsamen.

Warum sehe ich diese Verhaltensweisen und wie ermittle ich die optimale Puffergröße für die Aufgabe? Welche maximale Puffergröße gibt es?

bearbeiten

lief ich den folgenden Code, um die Laufzeiten unter Verwendung der oben genannten Dateigröße zu extrahieren:

Buffer Size 32. Done in 69s 
Buffer Size 64. Done in 69s 
Buffer Size 96. Done in 69s 
Buffer Size 128. Done in 70s 
Buffer Size 160. Done in 60s 
Buffer Size 192. Done in 57s 
Buffer Size 224. Done in 52s 
Buffer Size 256. Done in 50s 
Buffer Size 512. Done in 44s 
Buffer Size 768. Done in 40s 
Buffer Size 1024. Done in 39s 
Buffer Size 1280. Done in 41s 
Buffer Size 1536. Done in 44s 
Buffer Size 1792. Done in 40s 
Buffer Size 2048. Done in 39s 
Buffer Size 2304. Done in 41s 
Buffer Size 2560. Done in 41s 
Buffer Size 2816. Done in 42s 
Buffer Size 3072. Done in 43s 
Buffer Size 3328. Done in 43s 
Buffer Size 3584. Done in 45s 
Buffer Size 3840. Done in 44s 
Buffer Size 4096. Done in 45s 
Buffer Size 4352. Done in 47s 
Buffer Size 4608. Done in 46s 
Buffer Size 4864. Done in 46s 
Buffer Size 5120. Done in 48s 
Buffer Size 5376. Done in 49s 
Buffer Size 5632. Done in 51s 
Buffer Size 5888. Done in 51s 
Buffer Size 6144. Done in 52s 
Buffer Size 6400. Done in 54s 
Buffer Size 6656. Done in 53s 
Buffer Size 6912. Done in 55s 
Buffer Size 7168. Done in 55s 
Buffer Size 7424. Done in 56s 
Buffer Size 7680. Done in 57s 
Buffer Size 7936. Done in 65s 
Buffer Size 8192. Done in 62s 
Buffer Size 8448. Done in 63s 
Buffer Size 8704. Done in 64s 
Buffer Size 8960. Done in 64s 
Buffer Size 9216. Done in 66s 
Buffer Size 9472. Done in 66s 
Buffer Size 9728. Done in 68s 
Buffer Size 9984. Done in 68s 
Buffer Size 10240. Done in 69s 

Was:

startTime := Now(); 
myStreamReader := TStreamReader.Create(fileLocation, TEncoding.UTF8, True, numBytes); 
myStringList := TStringList.Create; 
try 
    myStringList.BeginUpdate; 
    try 
    myStringList.Clear; 
    while not myStreamReader.EndOfStream do 
     myStringList.Add(myStreamReader.ReadLine); 
    finally 
     myStringList.EndUpdate; 
    end; 
    finally 
    myStreamReader.Free; 
    end; 
processTime := Now() - startTime; 
myStringList.Free; 

Beispiel Laufzeiten wie extrahiert wurden RAM-Nutzung, Puffergrößen unter 256 führte zu einer Gesamtnutzung von 5 GB RAM und Puffergrößen über 1024 bei einer Gesamtnutzung von rund 3,5 GB. Zum Beispiel RAM-Nutzung mit einem 2kb, 4kb und 8kb Puffer; lesen Sie bitte:

this image

+1

Siehe [TStreamReader - schlechte Leistung] (http://qc.embarcadero.com/wc/qcmain.aspx?d=114824). –

+0

Etwas ist falsch, wenn größere Puffer langsamer sind. Das ist komisch. Müssen Sie wirklich in eine String-Liste laden? Wenn Sie das vermeiden könnten, würden Sie noch viel schneller gehen. –

+1

@DavidHeffernan, hat dies auf XE7 getestet und kann die schlechte Leistung von TStreamReader bestätigen. Die Verwendung von 'stringList.LoadFromFile()' ist> 5 mal schneller. –

Antwort

1

@Trojanian, der Code, den Sie oben erwähnen ist ähnlich wie Remy Lebeau Antwort in Ihrem früheren Post, TStringList.LoadFromFile - Exceptions with Large Text Files. Ich habe auch mit Remys Beispiel herumgespielt, das größere Dateien laden konnte, aber die Leistung für kleinere Dateien betrug etwa die Hälfte der Geschwindigkeit von TStrings.LoadFromFile. Meine eigenen Versuche, die Puffergröße umzuschalten, haben die Leistung nicht verbessert.

Dann fand ich den folgenden Code Beispiel Alternative to TStrings.LoadFromFile or TStringList.LoadFromFile, verwendet es einen 128kb Puffer und halbiert die Ladezeit meiner großen Dateien im Vergleich zu TStrings.LoadFromFile, das heißt x4 schneller als Ihr Code oben, wenn ich XE3 verwenden.

+0

Danke dafür - ich werde es mir ansehen. :-) – Trojanian

+2

In diesem Code sind einige Probleme zu beachten. Erstens, es führt 3 Suchen des Streams bei jeder Schleifeniteration durch, was für große Dateiströme teuer sein kann. Lieber die aktuelle 'Position' und 'Größe' in lokalen Variablen abrufen, bevor Sie die Schleife aufrufen, und diese dann während der Schleife verwenden.Außerdem verwendet die Schleife 'TStream.Read()', prüft jedoch nicht auf Fehler und nimmt an, dass die "ReadSize" -Byte immer gelesen wurde. Besser ist es stattdessen 'TStream.ReadBuffer()' zu verwenden. –

+0

Danke Remy für die Rückmeldung! – Lars