tFileStream读写之间循环时间差异巨大的原因是什么?



我尝试在文件中读取和写入股票数据。

相同的循环计数会产生巨大的差异。实际的写入循环需要近 30 分钟。

这仅仅是因为驱动器写入速度的物理限制吗?

有什么方法可以改善写作过程吗?

uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, System.Generics.Collections;
type
tSymbol = record
CloseList: TList<Integer>;
OpenList: TList<Integer>;
VolumeList: TList<Integer>;
end;
TForm1 = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
Memo1: TMemo;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
ReadList, WriteList: TList<tSymbol>;
end;
procedure TForm1.Button1Click(Sender: TObject); // it takes 45 seconds.
var
_FileStream: TFileStream;
i, j: Integer;
begin
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
ProgressBar1.Min := 0;
ProgressBar1.Max := 999;
_FileStream := TFileStream.Create('test', fmCreate);
for i := 0 to 999 do
begin
for j := 0 to 999 do
begin
_FileStream.Write(WriteList.List[i].CloseList.List[j], 4);
_FileStream.Write(WriteList.List[i].OpenList.List[j], 4);
_FileStream.Write(WriteList.List[i].VolumeList.List[j], 4);
end;
ProgressBar1.Position := i;
end;
_FileStream.Free;
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
end;
procedure TForm1.Button2Click(Sender: TObject); // it takes 6 seconds.
var
_FileStream: TFileStream;
_Close, _Open, _Volume: Integer;
_Symbol: tSymbol;
i, j: Integer;
begin
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
ProgressBar1.Min := 0;
ProgressBar1.Max := 999;
_FileStream := TFileStream.Create('test', fmOpenRead);
for i := 0 to 999 do
begin
_Symbol.CloseList := TList<Integer>.Create;
_Symbol.OpenList := TList<Integer>.Create;
_Symbol.VolumeList := TList<Integer>.Create;
for j := 0 to 999 do
begin
_FileStream.Read(_Close, 4);
_Symbol.CloseList.Add(_Close);
_FileStream.Read(_Open, 4);
_Symbol.OpenList.Add(_Open);
_FileStream.Read(_Volume, 4);
_Symbol.VolumeList.Add(_Volume);
end;
ReadList.Add(_Symbol);
ProgressBar1.Position := i;
end;
_FileStream.Free;
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
end;
procedure TForm1.FormCreate(Sender: TObject);
var
_Symbol: tSymbol;
i, j: Integer;
begin
ReadList := TList<tSymbol>.Create;
WriteList := TList<tSymbol>.Create;
_Symbol.CloseList := TList<Integer>.Create;
_Symbol.OpenList := TList<Integer>.Create;
_Symbol.VolumeList := TList<Integer>.Create;
for i := 0 to 999 do
begin
for j := 0 to 999 do
begin
_Symbol.CloseList.Add(0);
_Symbol.OpenList.Add(0);
_Symbol.VolumeList.Add(0);
end;
WriteList.Add(_Symbol);
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ReadList.Free;
WriteList.Free;
end;

使用缓冲文件 I/O。 在较大的块中读取/写入文件,根据需要管理每个块中的单个值。 德尔福甚至在柏林10.1及以后的TBufferedFileStream课上课。

此外,在填写列表时,请提前预先分配列表的容量,以避免在向列表中添加新项目时必须重新分配列表的内部数组的开销。

尝试更多类似的东西:

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, System.Generics.Collections;
type
tSymbol = record
CloseList: TList<Integer>;
OpenList: TList<Integer>;
VolumeList: TList<Integer>;
constructor Create(InitialCapacity: Integer);
procedure Cleanup;
end;
TForm1 = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
Memo1: TMemo;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
ReadList, WriteList: TList<tSymbol>;
end;
constructor tSymbol.Create(InitialCapacity: Integer);
begin
CloseList := TList<Integer>.Create;
CloseList.Capacity := InitialCapacity;
OpenList := TList<Integer>.Create;
OpenList.Capacity := InitialCapacity;
VolumeList: TList<Integer>.Create;
VolumeList.Capacity := InitialCapacity;
end;
procedure tSymbol.Cleanup;
begin
CloseList.Free;
OpenList.Free;
VolumeList.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
FS: TFileStream;
i, j, idx: Integer;
Block: array of Int32;
begin
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
ProgressBar1.Position := 0;
ProgressBar1.Min := 0;
ProgressBar1.Max := 1000;
ProgressBar1.Step := 1;
FS := T{Buffered}FileStream.Create('test', fmCreate);
try
SetLength(Block, 3 * 1000);
for i := 0 to WriteList.Count-1 do
begin
with WriteList[i] do
begin
idx := 0;
for j := 0 to 999 do
begin
Block[idx+0] := CloseList[j];
Block[idx+1] := OpenList[j];
Block[idx+2] := VolumeList[j];
Inc(idx, 3);
end;    
end;
FS.WriteBuffer(Block[0], SizeOf(Int32) * Length(Block));
ProgressBar1.StepIt;
end;
//FS.FlushBuffer;
finally
FS.Free;
end;
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
FS: TFileStream;
Symbol: tSymbol;
i, j, idx: Integer;
Block: array of Int32;
begin
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
for I := 0 to ReadList.Count-1 do
ReadList[I].Cleanup;
ReadList.Clear;
ProgressBar1.Position := 0;
ProgressBar1.Min := 0;
ProgressBar1.Max := 999;
ProgressBar1.Step := 1;
FS := T{Buffered}FileStream.Create('test', fmOpenRead or fmShareDenyWrite);
try    
SetLength(Block, 3 * 1000);
ReadList.Capacity := 1000;
for i := 0 to 999{(FS.Size div 12000) - 1} do
begin
FS.ReadBuffer(Block[0], SizeOf(Int32) * Length(Block));
Symbol := tSymbol.Create(1000);
try
idx := 0;
for j := 0 to 999 do
begin
Symbol.CloseList.Add(Block[idx+0]);
Symbol.OpenList.Add(Block[idx+1]);
Symbol.VolumeList.Add(Block[idx+2]);
Inc(idx, 3);
end;
ReadList.Add(Symbol);
except
Symbol.Cleanup;
raise;
end;
ProgressBar1.StepIt;
end;
finally
FS.Free;
end;
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Symbol: tSymbol;
i, j: Integer;
begin
ReadList := TList<tSymbol>.Create;
WriteList := TList<tSymbol>.Create;    
WriteList.Capacity := 1000;
for i := 0 to 999 do
begin
Symbol := tSymbol.Create(1000);
try
for j := 0 to 999 do
begin
Symbol.CloseList.Add(0);
Symbol.OpenList.Add(0);
Symbol.VolumeList.Add(0);
end;
WriteList.Add(Symbol);
except
Symbol.Cleanup;
raise;
end;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
i: Integer;
begin
if ReadList <> nil then
begin
for i := 0 to ReadList.Count-1 do
ReadList[i].Cleanup;
ReadList.Free;
end;
if WriteList <> nil then
begin
for i := 0 to WriteList.Count-1 do
WriteList[i].Cleanup;
WriteList.Free;
end;
end;

话虽如此,您可以考虑将 3 个整数值合并到另一个record中,这样您就不会浪费时间和资源来分配如此多的单个列表:

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, System.Generics.Collections;
type
tSymbolValues = record
Close: Integer;
Open: Integer;
Volume: Integer;
end;
tSymbol = record
Values: TList<tSymbolValues>;
constructor Create(InitialCapacity: Integer);
procedure Cleanup;
end;
TForm1 = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
Memo1: TMemo;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
ReadList, WriteList: TList<tSymbol>;
end;
constructor tSymbol.Create(InitialCapacity: Integer); 
begin
Values := TList<tSymbolValues>.Create;
Values.Capacity := InitialCapacity;
end;
procedure tSymbol.Cleanup;
begin
Values.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
FS: TFileStream;
i, j, idx: Integer;
Block: array of Int32;
begin
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
ProgressBar1.Position := 0;
ProgressBar1.Min := 0;
ProgressBar1.Max := 1000;
ProgressBar1.Step := 1;
FS := T{Buffered}FileStream.Create('test', fmCreate);
try
SetLength(Block, 3 * 1000);
for i := 0 to WriteList.Count-1 do
begin
with WriteList[i] do
begin
idx := 0;
for j := 0 to Values.Count-1 do
begin
with Values[j] do
begin
Block[idx+0] := Close;
Block[idx+1] := Open;
Block[idx+2] := Volume;
Inc(idx, 3);
end;
end;    
end;
FS.WriteBuffer(Block[0], SizeOf(Int32) * Length(Block));
ProgressBar1.StepIt;
end;
//FS.FlushBuffer;
finally
FS.Free;
end;
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
end;
procedure TForm1.Button2Click(Sender: TObject);
var
FS: TFileStream;
Symbol: tSymbol;
Values: tSymbolValues;
i, j, idx: Integer;
Block: array of Int32;
begin
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
for I := 0 to ReadList.Count-1 do
ReadList[i].Cleanup;
ReadList.Clear;
ProgressBar1.Position := 0;
ProgressBar1.Min := 0;
ProgressBar1.Max := 999;
ProgressBar1.Step := 1;
FS := T{Buffered}FileStream.Create('test', fmOpenRead or fmShareDenyWrite);
try    
SetLength(Block, 3 * 1000);
ReadList.Capacity := 1000;
for i := 0 to 999{(FS.Size div 12000) - 1} do
begin
FS.ReadBuffer(Block[0], SizeOf(Int32) * Length(Block));
Symbol := tSymbol.Create(1000);
try
idx := 0;
for j := 0 to 999 do
begin
Values.Open := Block[idx+0];
Values.Close := Block[idx+1];
Values.Volume := Block[idx+2];
Symbol.Values.Add(Values);
Inc(idx, 3);
end;
ReadList.Add(Symbol);
except
Symbol.Cleanup;
raise;
end;
ProgressBar1.StepIt;
end;
finally
FS.Free;
end;
Memo1.Lines.Add(FormatDateTime('hh:mm:ss', Time));
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Symbol: tSymbol;
Values: tSymbolValues;
i, j: Integer;
begin
ReadList := TList<tSymbol>.Create;
WriteList := TList<tSymbol>.Create;    
WriteList.Capacity := 1000;
for i := 0 to 999 do
begin
Symbol := tSymbol.Create(1000);
try
for j := 0 to 999 do
begin
Values.Open := 0;
Values.Close := 0;
Values.Volume := 0;
Symbol.Values.Add(Values);
end;
WriteList.Add(Symbol);
except
Symbol.Cleanup;
raise;
end;
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
var
i: Integer;
begin
if ReadList <> nil then
begin
for I := 0 to ReadList.Count-1 do
ReadList[i].Cleanup;
ReadList.Free;
end;
if WriteList <> nil then
begin
for I := 0 to WriteList.Count-1 do
WriteList[i].Cleanup;
WriteList.Free;
end;
end;

相关内容

最新更新