delphi - TFileStream 比 TMemoryStream 慢

这是我关于 SO 的第二个问题,我希望我的格式正确。

我在工作中发现 TFileStream 比 TMemoryStream 慢,我真的不知道为什么会这样。因此我决定做一些测试。

在我发现这种行为的应用程序中,我将所有文件加载到一个文件夹中,并且对于每个文件,我必须逐字节读取它。从 TFileStream 切换到 TMemoryStream 后,执行变得同步。为了测试这个,我做了下面的函数,其中相同的文件 (FileName) 被加载到 TStream Nr 次,每次流一次读取 Siz 字节直到结束(我真的很抱歉我的英语)。

我用来测试的功能是:

第一个是对TFileStream 的测试,因为它没有LoadFromFile 方法,我每次都必须创建和销毁它。

function TestFileStream(Nr, Siz: Integer): Double;
var
  sw: TStopWatch;
  Stream: TFileStream;
  I: Integer;
  buffer: TBytes;
begin
  sw := TStopWatch.StartNew;
  System.SetLength(buffer, Siz);
  for I := 0 to Nr - 1 do
    begin
      Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
      try
        Stream.Position := 0;
        while Stream.Position + Siz < Stream.Size do
          Stream.ReadBuffer(buffer, Siz);
      finally
        Stream.Free;
      end;
    end;
  Result := sw.Elapsed.TotalSeconds;
  sw.Stop;
end;

第二个是对TMemoryStream的测试,同样这次TMemoryStream被创建和销毁了Nr次。

function TestMemoryStream(Nr, Siz: Integer): Double;
var
  sw: TStopWatch;
  Stream: TMemoryStream;
  I: Integer;
  buffer: TBytes;
begin
  sw := TStopWatch.StartNew;
  System.SetLength(buffer, Siz);
  for I := 0 to Nr - 1 do
    begin
      Stream := TMemoryStream.Create;
      try
        Stream.LoadFromFile(FileName);
        Stream.Position := 0;
        while Stream.Position + Siz < Stream.Size do
          Stream.ReadBuffer(buffer, Siz);
      finally
        Stream.Free;
      end;
    end;
  Result := sw.Elapsed.TotalSeconds;
  sw.Stop;
end;

第三个是TMemoryStream的测试,这次TMemoryStream只创建了一次。

function TestKeepMemoryStream(Nr, Siz: Integer): Double;
var
  sw: TStopWatch;
  Stream: TMemoryStream;
  I: Integer;
  buffer: TBytes;
begin
  sw := TStopWatch.StartNew;
  System.SetLength(buffer, Siz);
  Stream := TMemoryStream.Create;
  try
    for I := 0 to Nr - 1 do
      begin
        Stream.LoadFromFile(FileName);
        Stream.Position := 0;
        while Stream.Position + Siz < Stream.Size do
          Stream.ReadBuffer(buffer, Siz);
      end;
  finally
    Stream.Free;
  end;
  Result := sw.Elapsed.TotalSeconds;
  sw.Stop;
end;

结果如下:

Nr = 100, Siz = 1
TFileStream:        27,8980448s
TMemoryStream:      0,1571709s
TMemoryStream Kept: 0,1607682s


Nr = 100, Siz = 16
TFileStream:        1,7674029s
TMemoryStream:      0,044709s
TMemoryStream Kept: 0,0432958s


Nr = 100, Siz = 4096
TFileStream:        0,0427971s
TMemoryStream:      0,0325959s
TMemoryStream Kept: 0,0316288s

令我感到奇怪的是 TMemoryStream 使用 TFileStream 加载文件,而 ReadBuffer 方法继承自 TStream ,所以就我的理解而言,应该没有区别。你有什么想法可以解释这一点吗?

最佳答案

如果您的 Siz 参数很小,TFileStream 每次都会访问磁盘以读取非常小的数据 block ,而在您的代码中 TMemoryStream 访问磁盘一次,然后从内存中读取小块。如果您将 Siz 变量设置为磁盘上文件的大小,您应该看不出有什么不同。

https://stackoverflow.com/questions/74150678/

相关文章:

javascript - 警告 IE11 用户他们的浏览器在 React 18 中不受支持

c# - ocelot api网关中的System.InvalidOperationExceptio

r - R中,如果有多个TRUE答案,选择第一个TRUE答案

c# - .NET 6 将参数检查替换为 ArgumentNullException.ThrowIf

javascript - 在 Javascript 中没有双 for 循环的情况下用对象数组中的 0

typescript - 如何为 Prisma 选择属性键入变量

python - 如何避免 NumPy 中的嵌套 for 循环?

r - 选定列乘以给定向量

javascript - 左侧条件分配

python - 确定谁拥有超过 80% 的给定发货人