Dynamisches 2D Array speichern

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Displaced
Beiträge: 83
Registriert: So 12. Jul 2009, 10:08

Dynamisches 2D Array speichern

Beitrag von Displaced »

Hallo,

Ich suche gerade eine Möglichkeit meine Array noch effizienter zu speichern.
Momentan schreib ich die immer erst in einen MemoryStream und speicher sie dann.
Dass sieht dann so aus, dass ich eine 256x256 große array in ner Schleife durchlaufen muss, und schreiben muss.
Wäre es möglich das ganze auch in einem Rutsch zu schreiben?
Ich meine 27ms ist nicht soo lang, aber das dauert halt beim Speichern von 100-1000 solcher Arrays seine Zeit.
In Delphi konnte man meines erarchtens

Code: Alles auswählen

ms.write(array, fieldsize * arrayX * arrayY);

machen.
Geht das auch irgendwie in Lazarus oder muss ich damit leben?
Gruß
Niko

Keifor
Beiträge: 31
Registriert: Sa 28. Aug 2010, 15:15
OS, Lazarus, FPC: pc-linux-gnu - Funtoo stable, L trunk, FPC trunk
CPU-Target: i686/x86_64

Re: Dynamisches 2D Array speichern

Beitrag von Keifor »

Die write Operation gibt es auch in freepascal in MemoryStream und FileStream,
man muß nur wegen dem dynamischen Feld etwas aufpassen und wie dieses Deklariert wurde.

Bspw. ist es ein Multidim. Feld, in dem jede Dimension aus Dynamischen Feldern besteht? Dann sieht das so aus. (wenn 256*256 immer fest ist, versteht sich, sonst wird das auslesen zum Ratespiel)

Code: Alles auswählen

type
  TField = array of Integer;
  T2DField = array of TField;
...
  for i:=0 to 255 do
    ms.write(field2d[i][0], 256*sizeof(Integer));


Für ein Multidim. Feld das Multidim Deklariert wurde sollte es einfacher gehn.

Code: Alles auswählen

type
  T2DField = array of array of Integer;
...
  ms.write(field2d[0,0], 256*256*sizeof(Integer));

Allerdings bin ich mir bei der Variante nicht sicher ob das Multidim. Feld intern als mehrere 1D Felder gehandhabt wird (also ob der Compiler das zerlegt oder als ein Speicherblock handhabt.).. wenn der Output also Müll ist, dann einfach die erste Variante nutzen.

Liegt also schlicht daran, ob es aus Einzelfeldern besteht oder nicht. Ein Einzelfeld ist zusammenhängend/als Reihe von Bytes schreibbar.
Weil sie Dynamisch sind, muß man den Feldindex des ersten Elementes angeben, damit von der ersten Position des dynamisch angeforderten Speichers geschrieben wird. Analog läufts mit dem Einlesen.

PS:
ms.write(array, fieldsize*X*Y) klappt ebenfalls. Halt nur für statische Felder (also Deklariert als array[1..256,1..256] of Integer z.B.)

carli
Beiträge: 657
Registriert: Sa 9. Jan 2010, 17:32
OS, Lazarus, FPC: Linux 2.6.x, SVN-Lazarus, FPC 2.4.0-2
CPU-Target: 64Bit

Re: Dynamisches 2D Array speichern

Beitrag von carli »

Bei dynamischen Arrays kann man sich sicher sein, dass benachbarte Elemente auch an benachbarten Adressen liegen.
Außerdem bleiben die Pointer so lange stabil bis die Größe des Arrays geändert wird. Ein dynamisches Array zu allokieren ist also nichts anderes zusammenhängenden Speicherbereich anzufordern, den man per Zeiger auf das erste Element auch als referenzgezählten Speicher missbrauchen kann.
Multidimensional geht das ganze aber schief, da ein array of array of foo ein Array von Zeigern ist. In dem Fall müsste man die inneren Arrays per Schleife einzeln per write/read abarbeiten.

Displaced
Beiträge: 83
Registriert: So 12. Jul 2009, 10:08

Re: Dynamisches 2D Array speichern

Beitrag von Displaced »

Die für mich schnellste Variante ist bislang mit move / einer dyn array of byte zu arbeiten.
Und dann den ganzen block ein mal zu schreiben. Das geht 50% schneller als jedes element zu schreiben.
Zudem ist write langsamer als move.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Dynamisches 2D Array speichern

Beitrag von mschnell »

Wer garantiert denn,m dass die Daten in einem dynamischen Array in einem Block angeordnet sind ? Sie können beliebig auf dem Heap verstreut sein.

-Michael

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Dynamisches 2D Array speichern

Beitrag von theo »

mschnell hat geschrieben:Wer garantiert denn,m dass die Daten in einem dynamischen Array in einem Block angeordnet sind ?


Was denn sonst? Wie das physikalisch gemacht wird, interessiert ja hier nicht.
Wenn du GetMem oder malloc machst, kriegst du ja auch keine Liste von Pointern, sondern nur einen.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Dynamisches 2D Array speichern

Beitrag von mschnell »

Ein 2D dynamisches Array ist physikalisch ein Array von Pointern

-Michael

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Dynamisches 2D Array speichern

Beitrag von theo »

mschnell hat geschrieben:Ein 2D dynamisches Array ist physikalisch ein Array von Pointern


Ja, 2D (bzw. Multidimensional) schon, davon hast du aber nicht gesprochen.

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: Dynamisches 2D Array speichern

Beitrag von mschnell »

theo hat geschrieben:Ja, 2D (bzw. Multidimensional) schon, davon hast du aber nicht gesprochen.
Siehe Thema: "Dynamisches 2D Array speichern"

-Michael

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Dynamisches 2D Array speichern

Beitrag von theo »

mschnell hat geschrieben:Siehe Thema: "Dynamisches 2D Array speichern"


Das hat doch aber carli um 3/9/2011, 14:22 schon festgestellt.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Dynamisches 2D Array speichern

Beitrag von Socke »

Displaced hat geschrieben:Zudem ist write langsamer als move.

Wenn du System.Move() mit Classes.TMemoryStream.Write() vergleichst, gibt es praktisch keinen Leistungsunterschied für den gesamten Speicherprozess. Der Unterschied liegt darin, dass TMemoryStream wenn nötig den Speicherbereich vergrößert und kopiert, was man natürlich vorbeugen kann (Eigenschaft: Size).

Man kann auch dafür sorgen, dass alle Arrays der zweiten Dimension in einem Block allokiert werden. C macht das zum Beispiel so, in Pascal ist das "nur" ein wenig im Speicherherumwühlen, um die Array-Referenzzählung und Längeninformationen manuell zu setzen.
Edith hat gesagt:

Code: Alles auswählen

program Project1;
// KEINE GARANTIE - Auf eigene Gefahr einsetzen
// Die Logik wurde bewusst nicht als Funktion gekapselt, damit der
// Benutzer wenigstens einen Teil der Logik verstehen muss.
type
   // Typen aus dynarr.inc lokal verfügbar machen
   pmydynarray = ^tmydynarray;
   tmydynarray = packed record
      refcount : ptrint;
      high : tdynarrayindex;
   end;
 
const
  INNER_LENGTH = 256;
  INNER_FIELD_SIZE = SizeOf(Longint);
var
  outer: array [0..255] of array of Longint;
  p, allarrays: Pointer;
  memsize: Sizeint;
  i: SizeInt;
 
begin
  fillchar(outer, length(outer) * Sizeof(outer[0]), 0);
  writeln('Outer array length: ', length(outer));
  writeln('Size of array record: ', sizeof(tmydynarray));
  // speicher reservieren
  //                       speicher für die nutzdaten      speicher für tmydynarray
  memsize := Length(outer)*INNER_LENGTH*INNER_FIELD_SIZE + Length(Outer)*sizeof(tmydynarray);
  writeln('allocating memory: ', memsize, ' Bytes');
 
  allarrays := GetMem(memsize);
  fillchar(PByte(allarrays)^, memsize, 1); // daten lesen
 
  // referenzzählung und längeninformation manuell setzen
  // streng genommen muss nur die referenzzählung überschrieben werden.
  for i := low(outer) to high(outer) do
  begin
    p := allarrays + i*INNER_LENGTH*INNER_FIELD_SIZE + i * sizeof(tmydynarray);
    pmydynarray(p)^.refcount := 1;
    pmydynarray(p)^.high := INNER_LENGTH - 1;
    Pointer(outer[i]) := p+Sizeof(tmydynarray); // typecast um refrenzzählung auszuschalten
  end;
 
  // Da oben ein fillchar() mit dem Wert 1 ausgeführt wird,
  // wird hier der Wert $01010101 ausgegeben
  writeln(outer[0][0]);
end.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Displaced
Beiträge: 83
Registriert: So 12. Jul 2009, 10:08

Re: Dynamisches 2D Array speichern

Beitrag von Displaced »

Wenn ich das richtig verstehe, allokiere ich damit eine Array im Speicher die ich dann nur noch richtig addressiere?
Damit müsste das auch mit einer "Array of array of" klappen oder?

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Dynamisches 2D Array speichern

Beitrag von Socke »

Displaced hat geschrieben:Wenn ich das richtig verstehe, allokiere ich damit eine Array im Speicher die ich dann nur noch richtig addressiere?
Damit müsste das auch mit einer "Array of array of" klappen oder?


Mein Code allokiert Speicher für mehrere Arrays, sodass diese direkt aufeinander folgen und initialisiert diese, wie der FPC es tun würde. Diese Arrays werden dann ihrerseits in einen Array eingetragen und schon ist der zweidimensionale Array (array of array) fertig. Mit dem kannst du arbeiten wie mit jedem mit "normalen" Pascal erstellten Array.

Prinzipiell ließe sich das auch für beliebig viele Dimensionen realisieren (=> Rekursion).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten