2014-11-23 3 views
5

Я запускаю Delphi RAD Studio XE2. Недавно я играл с файловыми потоками и нашел интересные результаты, которые привели меня к этому вопросу.Поток файлов в Delphi - Оптимальный размер буфера

Какой оптимальный размер буфера для TStreamReader в Delphi? Например, я загружаю 1 ГБ файл из 2 миллионов строк в форме doubleTABdoubleTABdouble. Если я загружу его в TStringList, используя следующий код, я получаю значительно разные результаты для разных размеров буфера. По результатам я имею в виду скорость обработки и использование ОЗУ.

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; 

Оптимальный размер буфера, кажется, между 1024 и 4096. Если он установлен меньше, чем 1024, кажется, замедляться линейно и, кажется, использовать больший объем оперативной памяти. Если он установлен выше 4096, он, по-видимому, замедляется экспоненциально.

Почему я вижу это поведение и как определить оптимальный размер буфера для задачи? Кроме того, каков максимальный размер буфера?

Редактировать

Я побежал следующий код для извлечения времени работы, используя вышеупомянутый размер файла:

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; 

Пример запуска раз были извлечены как:

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 

Что касается Использование ОЗУ, размеры буфера ниже 256, привели к общему использованию оперативной памяти Aroud объемом 5 ГБ и размерам буфера выше 1024 при общем использовании около 3,5 ГБ. Например, использование ОЗУ с буфером 2kb, 4kb и 8kb; пожалуйста, обратитесь к:

this image

+1

См. [TStreamReader - плохая производительность] (http://qc.embarcadero.com/wc/qcmain.aspx?d=114824). –

+0

Что-то не так, если более крупные буферы медленнее. Это странно. Вам действительно нужно загрузить в список строк? Если бы вы могли избежать этого, вы бы пошли гораздо быстрее. –

+1

@DavidHeffernan, протестировал это на XE7 и может подтвердить плохую производительность TStreamReader. Использование только 'stringList.LoadFromFile()'> в 5 раз быстрее. –

ответ

1

@Trojanian, код вы упоминаете выше похож на ответ Реми Лебо в вашем предыдущем посте, TStringList.LoadFromFile - Exceptions with Large Text Files. Я тоже возился с примером Реми, который мог загружать большие файлы, но производительность для файлов меньшего размера была примерно наполовину меньше TStrings.LoadFromFile. Мои собственные попытки переключить размер буфера не повысили производительность.

Тогда я нашел следующий пример кода, Alternative to TStrings.LoadFromFile or TStringList.LoadFromFile, он использует буфер 128KB и вдвое сократил время загрузки моих больших файлов по сравнению с TStrings.LoadFromFile, т.е. x4 быстрее, чем ваш код выше, когда я использую XE3.

+0

Спасибо за это - я посмотрю. :-) – Trojanian

+2

В этом коде есть некоторые проблемы. Во-первых, он выполняет 3 обращения к потоку на каждой итерации цикла, что может быть дорогостоящим для больших файловых потоков. Лучше извлекать текущие 'Position' и' Size' в локальные переменные перед входом в цикл, а затем использовать их во время цикла.Кроме того, цикл использует 'TStream.Read()', но не проверяет наличие ошибки и предполагает, что число ReadSize всегда считывалось. Лучше использовать 'TStream.ReadBuffer()' вместо этого. –

+0

Спасибо Remy за отзыв! – Lars