Delphi中的文件流 - 最佳缓冲区大小

Tro*_*ian 5 delphi buffer filestream delphi-xe2

我正在运行Delphi RAD Studio XE2.我最近一直在玩文件流,并发现一些有趣的结果引导我这个问题.

TStreamReaderDelphi中最佳缓冲区大小是多少?例如,我在表单中加载了一个200万行的1GB文件doubleTABdoubleTABdouble.如果我TStringList使用以下代码将其加载到a中,我会针对不同的缓冲区大小获得显着不同的结果.结果我的意思是处理速度和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;
Run Code Online (Sandbox Code Playgroud)

最佳缓冲区大小似乎介于1024和4096之间.如果设置小于1024,它似乎线性减速并且似乎使用更多RAM.如果它设置在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;
Run Code Online (Sandbox Code Playgroud)

示例运行时间被提取为:

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
Run Code Online (Sandbox Code Playgroud)

至于RAM使用情况,缓冲区大小低于256导致总共使用5GB RAM,缓冲区大小超过1024,总使用量约为3.5GB.例如,使用2kb,4kb和8kb缓冲区的RAM; 请参阅:

这个图片

Lar*_*ars 1

@Trojanian,您上面提到的代码与 Remy Lebeau 在上一篇文章TStringList.LoadFromFile - Exceptions with Large Text Files中的答案类似。我也摆弄了 Remy 的示例,它可以加载较大的文件,但较小文件的性能大约是TStrings.LoadFromFile. 我自己尝试切换缓冲区大小并没有提高性能。

然后我找到了以下代码示例,TStrings.LoadFromFile 或 TStringList.LoadFromFile 的替代方案,它使用 128kb 缓冲区,并将大文件的加载时间减半TStrings.LoadFromFile,即当我使用 XE3 时,比上面的代码快 4 倍。

  • 该代码中有一些问题需要注意。第一,它在每次循环迭代时执行 3 次流查找,这对于大型文件流来说成本高昂。最好在进入循环之前将当前的“Position”和“Size”检索到局部变量中,然后在循环时使用它们。此外,循环使用“TStream.Read()”,但不检查失败,并假设始终读取“ReadSize”字节数。最好使用 `TStream.ReadBuffer()` 来代替。 (2认同)