Einzelnen Beitrag anzeigen

Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#19

AW: RealTimeChart mit TeeChart und großer Datenmenge

  Alt 16. Dez 2015, 00:00
Jedoch wenn dieses Array 1 Mio überschreitet muss es als Ringpuffer weiterarbeiten,
also 0 löschen und alle anderen Werte nachschieben,
Ist zwar schon eine Weile her, aber ich kann mich noch erinnern, daß wir früher, wo Speicherzugriffe noch länger dauerten, einen Ringbuffer so implementiert haben, daß eben keine Daten verschoben werden mussten. Dazu wurde ein Array mit der Größe des Ringbuffers initialisiert und die Daten ganz normal über einen Indexzähler eingelesen. Erreicht der Zähler nun das Ende des Buffers wird er einfach wieder an den Anfang gesetzt und ein Merker gesetzt, der sagt, daß der Ringbuffer voll ist. Ab jetzt markiert der Zähler somit den Anfang des Ringbuffers. Daher auch der Name: man betrachtet die Daten wie einen Ring, auf dem man nur den Index verschiebt.

Will man nun die Daten des Ringbuffers lesen, unterscheidet man einen vollen und einen nicht-vollen Ringbuffer. Beim nicht-vollen wird ganz normal vom Anfang des Arrays bis zum Eintrag Zähler-1 gelesen. Beim vollen Ringbuffer liest man vom Zähler bis zum Ende des Arrays und hängt dann noch die Werte vom Anfang des Arrays bis zum Eintrag Zähler-1 dran.

Mit dieser Technik wird zwar das Auslesen des Ringbuffers etwas aufwändiger, aber das Anfügen eines neuen Wertes geht rattenschnell, da nicht jedesmal das ganze Array verschoben werden muss.

Eine einfache Implementation, die für diesen Zweck ausreichen müsste, ware in etwa sowas (nicht komplett durchgetestet!):

Delphi-Quellcode:
unit uRingBuffer;

interface

type
  TRingBuffer<T> = class
  private
    FData: TArray<T>;
    FFull: Boolean;
    FIndex: Integer;
    function CalcIndex(Value: Integer): Integer;
    function GetCount: Integer;
    function GetSize: Integer;
  public
    constructor Create(ASize: Integer);
    procedure AddValue(const AValue: T);
    function GetValue(AIndex: Integer): T;
    function GetValues(AIndex, ACount: Integer): TArray<T>;
    property Count: Integer read GetCount;
    property Size: Integer read GetSize;
  end;

implementation

constructor TRingBuffer<T>.Create(ASize: Integer);
begin
  inherited Create;
  SetLength(FData, ASize);
  FIndex := 0;
  FFull := false;
end;

procedure TRingBuffer<T>.AddValue(const AValue: T);
begin
  FData[FIndex] := AValue;
  Inc(FIndex);
  if FIndex > High(FData) then begin
    FIndex := 0;
    FFull := true;
  end;
end;

function TRingBuffer<T>.GetValue(AIndex: Integer): T;
begin
  Result := FData[CalcIndex(AIndex)];
end;

function TRingBuffer<T>.GetValues(AIndex, ACount: Integer): TArray<T>;
var
  idx: Integer;
  I: Integer;
begin
  Assert(AIndex + ACount <= Count, 'buffer has not enough elements');
  SetLength(Result, ACount);
  idx := CalcIndex(AIndex);
  for I := 0 to ACount - 1 do begin
    Result[I] := FData[idx];
    Inc(idx);
    if idx > High(FData) then begin
      idx := 0;
    end;
  end;
end;

function TRingBuffer<T>.CalcIndex(Value: Integer): Integer;
begin
  Result := Value;
  if FFull then begin
    Result := Result + FIndex;
    if Result > High(FData) then begin
      Result := Result - Size;
    end;
  end;
end;

function TRingBuffer<T>.GetCount: Integer;
begin
  if FFull then begin
    Result := Size;
  end
  else begin
    Result := FIndex;
  end;
end;

function TRingBuffer<T>.GetSize: Integer;
begin
  Result := Length(FData);
end;

end.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat