2014-11-23 31 views
5

Sto eseguendo Delphi RAD Studio XE2. Recentemente ho giocato con i file stream e ho trovato alcuni risultati interessanti che mi hanno portato a questa domanda.Streaming file in Delphi - Dimensione buffer ottimale

Qual è la dimensione del buffer ottimale per un TStreamReader in Delphi? Ad esempio, sto caricando un file da 1 GB di 2 milioni di righe nel modulo doubleTABdoubleTABdouble. Se lo carico in un TStringList utilizzando il codice seguente, ottengo risultati estremamente variabili per diverse dimensioni del buffer. Con i risultati intendo velocità di elaborazione e utilizzo della RAM.

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; 

La dimensione di buffer ottimale sembra essere tra 1024 e 4096. Se è impostato inferiori a 1024 sembra rallentare linearmente e sembra usare più RAM. Se è impostato sopra il 4096, sembra rallentare in modo esponenziale.

Perché vedo questi comportamenti e come posso determinare la dimensione ottimale del buffer per l'attività? Inoltre, qual è la dimensione massima del buffer?

Modifica

Ho eseguito il seguente codice per estrarre i tempi di esecuzione utilizzando la dimensione del file di cui sopra:

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; 

esempio tempi di esecuzione sono stati estratti come:

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 

Per quanto riguarda L'utilizzo della RAM, le dimensioni del buffer inferiori a 256 hanno comportato un utilizzo totale di 5 GB di RAM e dimensioni del buffer superiori a 1024 in un utilizzo totale di circa 3,5 GB. Ad esempio l'utilizzo della RAM con un buffer da 2kb, 4kb e 8kb; Si prega di fare riferimento a:

this image

+1

Vedere [TStreamReader - prestazioni errate] (http://qc.embarcadero.com/wc/qcmain.aspx?d=114824). –

+0

Qualcosa non va se i buffer più grandi sono più lenti. Quello è strano. Hai davvero bisogno di caricare in una lista di stringhe? Se potessi evitare che andresti ancora più veloce. –

+1

@DavidHeffernan, testato su XE7 e in grado di confermare le cattive prestazioni di TStreamReader. L'uso di 'stringList.LoadFromFile()' è> 5 volte più veloce. –

risposta

1

@Trojanian, il codice si parla sopra è simile alla risposta di Remy Lebeau nel post precedente, TStringList.LoadFromFile - Exceptions with Large Text Files. Anch'io armeggiavo con l'esempio di Remy che poteva caricare file più grandi, ma le prestazioni per file più piccoli erano circa la metà della velocità di TStrings.LoadFromFile. I miei tentativi di commutare la dimensione del buffer non hanno migliorato le prestazioni.

Poi ho trovato il seguente esempio di codice, Alternative to TStrings.LoadFromFile or TStringList.LoadFromFile, utilizza un buffer di 128 KB e dimezzato il carico-tempo dei miei file di grandi dimensioni rispetto al TStrings.LoadFromFile, vale a dire x4 più veloce del codice di cui sopra quando uso XE3.

+0

Grazie per questo - darò un'occhiata. :-) – Trojanian

+2

Ci sono alcuni problemi da tenere presente in quel codice. Uno, esegue 3 ricerche del flusso su ogni iterazione del ciclo, che può essere costoso per i flussi di file di grandi dimensioni. È meglio recuperare la posizione corrente e le dimensioni in variabili locali prima di entrare nel ciclo, quindi utilizzarle durante il ciclo.Inoltre, il ciclo utilizza 'TStream.Read()' ma non verifica il fallimento e presuppone che il numero di byte di ReadSize sia sempre letto. Meglio usare 'TStream.ReadBuffer()' invece. –

+0

Grazie Remy per il feedback! – Lars