【问题标题】:File Streaming in Delphi - Optimum Buffer SizeDelphi 中的文件流式传输 - 最佳缓冲区大小
【发布时间】:2014-11-23 03:30:41
【问题描述】:

我正在运行 Delphi RAD Studio XE2。我最近一直在玩文件流,发现一些有趣的结果让我想到了这个问题。

在 Delphi 中,TStreamReader 的最佳缓冲区大小是多少?例如,我正在以doubleTABdoubleTABdouble 的形式加载一个包含 200 万行的 1GB 文件。如果我使用以下代码将其加载到 TStringList 中,对于不同的缓冲区大小,我会得到显着不同的结果。我所说的结果是指处理速度和 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;

最佳缓冲区大小似乎在 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;

示例运行时间提取为:

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

就 RAM 使用而言,缓冲区大小低于 256 会导致总使用量约为 5GB RAM,而缓冲区大小高于 1024 会导致总使用量约为 3.5GB。例如 2kb、4kb 和 8kb 缓冲区的 RAM 使用情况;请参考:

【问题讨论】:

  • 如果缓冲区越大越慢,就会出现问题。这很奇怪。您真的需要加载到字符串列表中吗?如果你能避免这种情况,你会走得更快。
  • @DavidHeffernan,在 XE7 上进行了测试,可以确认 TStreamReader 的性能不佳。仅使用 stringList.LoadFromFile() 速度会快 5 倍以上。
  • 但是我的测试没有使用足够大的文件而导致 LoadFromFile 异常失败。
  • 这肯定有一些奇怪的事情发生 - 请参阅上面最近的编辑。

标签: delphi buffer delphi-xe2 filestream


【解决方案1】:

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

然后我找到了下面的代码示例Alternative to TStrings.LoadFromFile or TStringList.LoadFromFile,它使用了一个 128kb 的缓冲区,与TStrings.LoadFromFile 相比,我的大文件的加载时间减半,也就是说,当我使用 XE3 时,它比上面的代码快 4 倍。

【讨论】:

  • 谢谢你 - 我会看看。 :-)
  • 该代码中有一些问题需要注意。第一,它在每次循环迭代中执行 3 次流搜索,这对于大文件流来说可能代价高昂。最好在进入循环之前将当前的PositionSize 检索到局部变量中,然后在循环时使用它们。此外,循环使用TStream.Read(),但不检查失败,并假定始终读取ReadSize 字节数。最好改用TStream.ReadBuffer()
  • 感谢雷米的反馈!
  • @Lars,对不起,我花了这么长时间才在这里回复你。我玩过这个,它比问题中的代码快得多。我还添加了更改链接代码中缓冲区大小的功能,发现 128kb 是最佳的。我很好奇这是为什么。就我个人而言,我发现记忆管理有点神秘的黑暗艺术。我会仔细阅读的。
猜你喜欢
  • 1970-01-01
  • 2010-12-05
  • 2011-03-03
  • 1970-01-01
  • 2014-08-22
  • 1970-01-01
  • 1970-01-01
  • 2018-10-14
  • 2012-02-06
相关资源
最近更新 更多