我们拥有自己的数据流算法,包括一些元数据+记录+字段值。
目前我们使用TStream并写入以向流添加值。 现在我想知道这次使用某种技术是否可以更快地进行消耗操作。
修改:我们只是将数据追加到最后,而不是移动或寻找。
我想到的一些事情是:
我们正在以#0#0#0#1的形式向TStream和二进制数据添加字符串。
然后通过TCP传输数据,因此不是写入文件。
那么最好的方法是什么?
答案 0 :(得分:5)
首先,您假设TStream
是瓶颈。您需要对代码进行概要分析,例如使用AQTime,以确定瓶颈的确切位置。不要做出假设。
其次,您实际使用的TStream
是什么类型的? TMemoryStream
? TFileStream
?别的什么?不同的流类型处理内存不同。 TMemoryStream分配一个内存缓冲区,并在缓冲区填满时按预设的字节数增长。另一方面,TFileStream
根本不使用任何内存,只是直接写入文件并让操作系统处理任何缓冲。
无论您使用哪种类型的流,您可以尝试的一件事是实现您自己的自定义TStream
类,该类具有内部固定大小的缓冲区和指向您的真实目标TStream
对象的指针。然后,您可以将自定义类的实例传递给算法。让您的类覆盖TStream::Write()
方法将输入数据复制到其缓冲区中直到它填满,然后您可以Write()
缓冲区到目标TStream
并清除缓冲区。你的算法永远不会知道差异。 TMemoryStream
和TFileStream
都可以从额外的缓冲中受益 - 更少的大写意味着更高效的内存分配和文件I / O.例如:
type
TMyBufferedStreamWriter = class(TStream)
private
fDest: TStream;
fBuffer: array[0..4095] of Byte;
fOffset: Cardinal;
public
constructor Create(ADest: TStream);
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
procedure FlushBuffer;
end;
uses
RTLConsts;
constructor TMyBufferedStreamWriter.Create(ADest: TStream);
begin
fDest := ADest;
end;
function TMyBufferedStreamWriter.Read(var Buffer; Count: Longint): Longint;
begin
Result := 0;
end;
function TMyBufferedStreamWriter.Write(const Buffer; Count: Longint): Longint;
var
pBuffer: PByte;
Num: Cardinal;
begin
Result := 0;
pBuffer := PByte(@Buffer);
while Count > 0 do
begin
Num := Min(SizeOf(fBuffer) - fOffset, Cardinal(Count));
if Num = 0 then FlushBuffer;
Move(pBuffer^, fBuffer[fOffset], Num);
Inc(fOffset, Num);
Inc(pBuffer, Num);
Dec(Count, Num);
Inc(Result, Num);
end;
end;
procedure TMyBufferedStreamWriter.FlushBuffer;
var
Idx: Cardinal;
Written: Longint;
begin
if fOffset = 0 then Exit;
Idx := 0;
repeat
Written := fDest.Write(fBuffer[Idx], fOffset - Idx);
if Written < 1 then raise EWriteError.CreateRes(@SWriteError);
Inc(Idx, Written);
until Idx = fOffset;
fOffset := 0;
end;
Writer := TMyBufferedStreamWriter.Create(RealStreamHere);
try
... write data to Writer normally as needed...
Writer.FlushBuffer;
finally
Writer.Free;
end;
答案 1 :(得分:4)
Size
属性预先设置为足够大的数量来避免这种情况。 答案 2 :(得分:2)
覆盖TMemoryStream并删除Size和Capacity的限制。并且不要调用TMemoryStream.Clear但是调用TMemoryStream.SetSize(0)
type
TMemoryStreamEx = class(TMemoryStream)
public
procedure SetSize(NewSize: Longint); override;
property Capacity;
end;
implementation
{ TMemoryStreamEx }
procedure TMemoryStreamEx.SetSize(NewSize: Integer);
var
OldPosition: Longint;
begin
if NewSize > Capacity then
inherited SetSize(NewSize)
else
begin
OldPosition := Position;
SetPointer(Memory, NewSize);
if OldPosition > NewSize then
Seek(0, soFromEnd);
end;
end;