2012-03-29 7 views
3

우리는 일부 메타 데이터 + 레코드 + 필드 값을 포함하는 자체 데이터 스트리밍 알고리즘을 가지고 있습니다.최적 버퍼 스트림 쓰기 프로세스

현재 TStream을 사용하여 스트림에 값을 추가합니다. 이제는 기술을 사용하여이 시간을 단축 할 수 있는지 궁금합니다.

편집 : 우리는 이동하거나 추구하지 끝에 데이터를 추가합니다. 내가 생각하고 있었는데

몇 가지가 있습니다 :

  • 가 데이터를 복사하는 일부 대형 메모리 할당 된 버퍼 buf를 스트림을 사용하지 않습니다 우리는 버퍼 크기를 넘어 가면, 문제는 우리가 일부 이주 할 필요가있다 새로운 메모리 공간.
  • 일부 크기에 # 0s가 채워진 스트림을 사용한 다음 값을 추가하기 시작합니다. TStream은 필자가 쓰기를 할 때마다 TStream이 자신의 버퍼를 할당해야한다는 것입니다. (실제로 어떻게 작동하는지 모르지만 궁금합니다 ...)

TStream 및 바이너리 데이터에 문자열을 추가합니다 예를 들어 # 0 # 0 # 0 # 1 형식으로 표시됩니다.

데이터는 TCP를 통해 전송되므로 파일에 쓰는 것이 아닙니다.

그래서 가장 좋은 방법은 무엇입니까?

+0

메모리 스트림에 대해 이야기하고 계십니까? –

+0

데이터 양이 많으면 (200MB 이상) TFileStream을 권장합니다. 그렇지 않으면 TMemoryStream이 가장 빠르고 쉬운 방법입니다. TFile | MemoryStream을 사용하고 (레코드 수 등) 정보를 유지해야하는 경우 스트림 시작 부분에 헤더를 추가하고 모든 업데이트 후에 커서 위치를 처음으로 재설정 한 다음 스트림을 읽고 오버라이드하십시오. 위치 : = Stream.Size; <- bam 스트림의 끝에 있고 데이터를 계속 추가합니다. 레코드 삭제의 가능성이있는 경우 각 레코드에는 플래그 (삭제됨 : Boolean)가 포함 된 헤더가 필요합니다. – ComputerSaysNo

+0

@Dorin : 우리는 소켓을 사용하여 보내기 때문에 TFileStream이 옵션이 아닌 것으로 보입니다. 문제는 스트림 + 쓰기를 사용하여 수행하는 방법이 아닙니다. 이미 사용하고 있습니다. 문제는 더 빠르게 수행 할 수있는 방법이있는 경우입니다. –

답변

2

크기 및 용량의 제한을 제거하십시오. TMemoryStream.Clear를 호출하지 말고 TMemoryStream.SetSize()를 호출하십시오.

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; 
4
  1. 실제로 느린 곳을 보려면 프로파일 러를 사용하십시오.
  2. 스트림의 크기를 늘리기 위해 다중 재 할당이 실제로 발생하는 경우 Size 속성을 충분히 큰 값으로 설정하여이를 피할 수 있습니다.
  3. 메모리 버퍼를 사용하는 것이 명백한 차이를 만들 수있는 유일한 경우는 FileStreams를 사용하는 경우 다른 모든 사용 가능한 스트림이 이미이 작업을 수행하고 있다는 것입니다.
+0

) TStringStream에 대해서만 문서 (Delphi 7)를 읽으면 Size 속성을 설정할 수 있으며 이것을 사용할 수 있습니다. 또한 프로파일 러 경로를 탐색해야합니다 –

+0

@DanielLuyo, D7 소스를 보았습니다. TStream에는 자손이 사용할 수있는 (읽기 또는 쓰기) 공용 크기 속성이 있습니다. –

4

먼저, TStream이 병목 현상이라고 가정합니다. AQTime과 같은 코드를 프로파일 링하여 병목 현상이 실제로 어디에 있는지 파악해야합니다. 가정하지 마십시오.

두 번째로 실제로 사용하고있는 TStream의 유형은 무엇입니까? TMemoryStream? TFileStream? 다른 것? 다른 스트림 유형은 메모리를 다르게 처리합니다. TMemoryStream은 메모리 버퍼를 할당하고 버퍼가 채워질 때마다 미리 설정된 크기만큼 메모리 버퍼를 늘립니다. 반면에 TFileStream은 메모리를 전혀 사용하지 않고 단지 파일에 직접 씁니다. 그리고 OS가 버퍼링을 처리하게합니다.

사용하는 스트림의 유형에 관계없이 시도해 볼 수있는 한 가지 방법은 내부 고정 크기 버퍼와 실제 대상인 TStream 개체에 대한 포인터가있는 사용자 지정 TStream 클래스를 구현하는 것입니다. 그런 다음 사용자 정의 클래스의 인스턴스를 알고리즘에 전달할 수 있습니다. 클래스가 가득 채워질 때까지 TStream::Write() 메서드를 재정 의하여 해당 입력 데이터를 버퍼에 복사 한 다음 Write() 버퍼를 대상에 TStream 버퍼로 지울 수 있습니다. 귀하의 알고리즘은 그 차이를 결코 알 수 없습니다. TMemoryStreamTFileStream 모두 추가 버퍼링의 이점을 누릴 수 있습니다. 쓰기가 적을수록 메모리 할당과 파일 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; 
관련 문제