Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Tutorials und Kurse (https://www.delphipraxis.net/36-tutorials-und-kurse/)
-   -   Delphi Arrayoperationen beschleunigen (https://www.delphipraxis.net/81264-arrayoperationen-beschleunigen.html)

himitsu 23. Nov 2006 17:23


Arrayoperationen beschleunigen
 
Es ist ja wohl bekannt, daß bei vielen Änderungen der Arraygröße eine Menge Zeit draufgeht.

Dagegen gibt es eigentlich nur ein Mittel > die Anzahl der Änderungen muß verringert werden, so daß nicht gleich bei jeder kleinen Änderung der gesamte Arrayinhalt hin- und herkopiert wird.



Als Erstes könnte man es mal mit einem anderem Memory-Manager versuchen (z.B. Hier im Forum suchenFastMM),
allerdings ist es da nicht möglich das Verhalten an eigene Bedürfnisse anzupassen.


Also wäre es wohl nicht schlecht, wenn selber das Verhalten geändert wird.

1.) Verwendete und tatsächliche Größe unabhängig verwalten:
Wozu noch eine extra Variable für den verwendeten Bereich nötig wäre.
Code:
[b][color=blue]// Definition[/color][/b]
[b]Var[/b] MyArray: [b]Array of[/b] XXX;
  MyArray_Length: Integer;

[b][color=blue]// SetLength(MyArray, NewLength);[/color][/b]
MyArray_Length := NewLength;
SetLength(MyArray, [color=green](NewLength + $1FFF) [b]and not[/b] $1FFF[/color]);

[b][color=blue]// Length(MyArray)[/color][/b]
MyArray_Length

[b][color=blue]// High(MyArray)[/color][/b]
MyArray_Length - 1

[b][color=blue]// MyArray[Index][/color][/b]
MyArray[Index]


2.) Verwendete Größe mit Array speichern:
z.B. am Ende/nach den Array-Daten
Keine weitere Variable nötig, somit wären die Funktionen auf mehrere Arrays anwendbar.
Code:
[b][color=blue]// Definition[/color][/b]
[b]Type[/b] TMyArray = [b]Array of[/b] XXX;

[b]Var[/b] MyArray: TMyArray;

[b]Function[/b] Length_(Const A: TMyArray): Integer;
  [b]Begin[/b]
    [b]If[/b] A = nil [b]Then[/b] Result := 0
    [b]Else[/b] Result := PInteger(@A[High(A)])^;
  [b]End[/b];

[b]Function[/b] High_(Const A: TMyArray): Integer;
  [b]Begin[/b]
    Result := Length_(A) - 1;
  [b]End[/b];

[b]Procedure[/b] SetLength_([b]Var[/b] A: TMyArray; i: Integer);
  [b]Begin[/b]
    [b]If[/b] A <> nil [b]Then[/b] PInteger(@A[High(A)])^ := 0;
    [b]If[/b] i > 0 [b]Then[/b] [b]Begin[/b]
      SetLength(A, ([color=green](i + $1FFF) [b]and not[/b] $1FFF[/color]) + 1);
      PInteger(@A[High(A)])^ := i;
    [b]End Else[/b] A := nil;
  [b]End[/b];

[b][color=blue]// SetLength(MyArray, NewLength);[/color][/b]
SetLength_(MyArray, NewLength);

[b][color=blue]// Length(MyArray)[/color][/b]
Length_(MyArray)

[b][color=blue]// High(MyArray)[/color][/b]
High_(MyArray)

[b][color=blue]// MyArray[Index][/color][/b]
MyArray[Index]
Dieses Beispiel ist nur für SizeOf(XXX) >= 4,
wenn SizeOf(XXX) kleiner als SizeOf(Integer) ist, dann muß natürlich mehr als nur ein Feld für die zu speichernde Größenangabe verwendet werden.
Code:
[b]Function[/b] Length_(Const A: TMyArray): Integer;
  [b]Begin[/b]
    [b]If[/b] A = nil [b]Then[/b] Result := 0
    [b]Else[/b] Result := PInteger(@A[[color=red]Length(A) - 2{4}[/color]])^;
  [b]End[/b];

[b]Procedure[/b] SetLength_([b]Var[/b] A: TMyArray; i: Integer);
  [b]Begin[/b]
    [b]If[/b] A <> nil [b]Then[/b] PInteger(@A[[color=red]Length(A) - 2{4}[/color]])^ := 0;
    [b]If[/b] i > 0 [b]Then[/b] [b]Begin[/b]
      SetLength(A, ([color=green](i + $1FFF) [b]and not[/b] $1FFF)[/color] + [color=red]2{4}[/color]);
      PInteger(@A[[color=red]Length(A) - 2{4}[/color]])^ := i;
    [b]End Else[/b] A := nil;
  [b]End[/b];

[b][color=blue]// 2 für SizeOf(XXX)=2, oder SizeOf(XXX)=3
// 4 für SizeOf(XXX)=1[/color][/b]


3.) Größenangabe direkt im Array ändern:
Vorteil zum vorherigen (2) Vorgehen wäre, daß hier nur SetLength geändert werden muß.
Code:
[b][color=blue]// Definition[/color][/b]
[b]Type[/b] TMyArray = [b]Array of[/b] XXX;

[b]Var[/b] MyArray: TMyArray;

[b]Procedure[/b] SetLength_([b]Var[/b] A: TMyArray; i: Integer);
  [b]Begin[/b]
    [b]If[/b] A <> nil [b]Then[/b] PInteger(Integer(A) - SizeOf(Integer))^ :=
      [color=green](PInteger(Integer(A) - SizeOf(Integer))^ + $1FFF) [b]and not[/b] $1FFF[/color];
    SetLength(A, [color=green](i + $1FFF) [b]and not[/b] $1FFF[/color]);
    [b]If[/b] A <> nil [b]Then[/b] PInteger(Integer(A) - SizeOf(Integer))^ := i;
  [b]End[/b];

[b][color=blue]// SetLength(MyArray, NewLength);[/color][/b]
SetLength_(MyArray, NewLength);

[b][color=blue]// Length(MyArray)[/color][/b]
Length(MyArray)

[b][color=blue]// High(MyArray)[/color][/b]
High(MyArray)

[b][color=blue]// MyArray[Index][/color][/b]
MyArray[Index]


4.) Wer nicht direct im Array "rumpfuschen" möchte, könnte es auch mit einer Klasse versuchen.
Allerdings wird hierfür dann zusätzlich noch der Constructor und Destructor benötigt.
Code:
[b]Type[/b] TMyArrayClass = [b]Class[/b]
    Private
      A: [b]Array of[/b] XXX;
      ALen: Integer;
      [b]Function[/b] GetField(i: Integer): XXX;
      [b]Procedure[/b] SetField(i: Integer; Value: XXX);
    Public
      [b]Procedure[/b] SetLen(i: Integer);
      [b]Function[/b] Len: Integer;
      [b]Property[/b] LenX: Integer [b]Read[/b] Len [b]Write[/b] SetLen;
      [b]Property[/b] Field[i: Integer]: XXX [b]Read[/b] GetField [b]Write[/b] SetField; [b]Default[/b];
  [b]End[/b];

[b]Function[/b] TMyArrayClass.GetField(i: Integer): XXX;
  [b]Begin[/b]
    Result := A[i];
  [b]End[/b];

[b]Procedure[/b] TMyArrayClass.SetField(i: Integer; Value: XXX);
  [b]Begin[/b]
    A[i] := Value;
  [b]End[/b];

[b]Procedure[/b] TMyArrayClass.SetLen(i: Integer);
  [b]Begin[/b]
    SetLength(A, [color=green](i + $1FFF) [b]and not[/b] $1FFF[/color]);
    ALen := i;
  [b]End[/b];

[b]Function[/b] TMyArrayClass.Len: Integer;
  [b]Begin[/b]
    Result := ALen;
  [b]End[/b];

Var MyArray: TMyArrayClass;

[b][color=blue]// Initialisieren[/color][/b]
MyArray := TMyArrayClass.Create;

[b][color=blue]// SetLength(MyArray, NewLength);[/color][/b]
MyArray.SetLen(NewLength);
[b][color=blue]{oder}[/color][/b] MyArray.LenX := NewLength;

[b][color=blue]// Length(MyArray)[/color][/b]
MyArray.Len
[b][color=blue]{oder}[/color][/b] MyArray.LenX

[b][color=blue]// High(MyArray)[/color][/b]
MyArray.High

[b][color=blue]// MyArray[Index][/color][/b]
MyArray[Index]
[b][color=blue]{oder}[/color][/b] MyArray.Field[Index]

[b][color=blue]// Finalisieren[/color][/b]
MyArray.Free;






Fazit:
Aus OOP-Sicht wäre 4. zu bevorzugen,
auch wenn da vieles zu beachten und zu verändern ist.

Bei 1. ist zwar guz zu sehn was gemacht wird, allerdings mu da jedes SetLength, Length und High geändert werden.

2. ist im Grunde nicht zu empfehlen, da dort das Array besser mit SelLength_(MyArray, 0) freigegeben werden sollte, vorallem wenn im Typ dynamische Stukturen enthalten sind, welche von FinalizeArray behandelt werden (z.B. Strings), da es sonst Probleme mit dem Typ-Fremden Integer (der Längenangabe am Ende) geben könnte.
Schließlich wird aus gutem Grund die Größenangabe aus dem Array gelöscht, bevor die Größe geändert wird. :warn:
Delphi-Quellcode:
If A <> nil Then PInteger(@A[High(A)])^ := 0;

Ich selber verwende gerne 3., da hierbei nur SetLength ersetzt werden muß und alles andere unverändert bleibt.
Außerdem kann dieses Array überall so verwendet werden, als wäre es ein ganz normalles Array. :)
Manchmal auch 1., da es ja im Grunde genau das Selbe wie 2. ist, nur halt etwas schneller.




Schrittweite:
In den Beispielen wird die Arraygröße jeweils in Schritten von 1024 geändert.

Es sind natürlich auch andere Werte möglich,
aber im allgemeinen sind 2er-Potenzen idealer, da dort binär (mit AND) gerechnet werden kann,
wärend sonst mathematische Rechnungen (mit MOD und *) nötig sind.

Also einmal ein "schnelles" AND (das NOT wird mit einkopiliert),
oder zweimal "langsame" DIV/MUL.

Code:
[b][color=blue]// binär (nur bei 2er-Potenzen)[/color][/b]
[color=green](i + (AllocSize - 1)) [b]and not[/b] (AllocSize - 1)[/color]
[b][color=blue]{=}[/color][/b] [color=green](i + $*****) [b]and not[/b] $*****[/color]

[b][color=blue]// matematisch[/color][/b]
[color=darkgreen]((i + (AllocSize - 1)) [b]div[/b] AllocSize) * AllocSize[/color]

negaH 23. Nov 2006 17:30

Re: Arrayoperationen beschleunigen
 
Fairerweise muß noch noch Methode 5 erwähnen ;)

Delphi-Quellcode:

var
  Count: Integer;
  MyArray: array of anytype;
begin
  Count := 0;
  while xyz do
  begin
    if Count mod 256 = 0 then
      SetLength(MyArray, Count +256); // 256 Elemente preallozieren
    MyArray[Count] := XYZ;
    Inc(Count);
  end;
  SetLength(MyArray, Count);
end;
Dh. wenn der Programierer weiß das die Reallokation der dyn. arrays ein Problem darstellt so reichen im Allgemeinen 3 zusätzliche Zeilen Sourcecode um das zu optimierern. Der Effekt ist der selbe wie bei den komplizierten Methode oben ;)

Gruß hagen

DP-Maintenance 23. Nov 2006 17:32

DP-Maintenance
 
Dieses Thema wurde von "Dax" von "Neuen Beitrag zur Code-Library hinzufügen" nach "Tutorials und Kurse" verschoben.
Das ist wohl eher ein Tutorial.. :)

Der_Unwissende 23. Nov 2006 17:54

Re: Arrayoperationen beschleunigen
 
Zitat:

Zitat von negaH
Fairerweise muß noch noch Methode 5 erwähnen ;)

Dann aber auch Methode 6, die etwas mehr für die enttäuschten OOPler aus Methode 4 ist :wink:

Delphi-Quellcode:

var
  MyArray: TList;
begin
  MyArray := TList.Create;

  // schreiben:
  while xyz do
  begin
    MyArray.Add(abcd);
  end;
 
  // und wahlfrei lesen:
  doFoo(AnyType(MyArray[abc])^);
  ....
end;
Auch nur ein Array, dass dyn. wächst und schrumpft, aber man selbst muss sich halt darum nicht kümmern.

Gruß Der Unwissende

himitsu 23. Nov 2006 18:08

Re: Arrayoperationen beschleunigen
 
Upps ... tschuldsche, hast ja recht DAX :oops:

Aber zu Hagens ... deines funktioniert nur, wenn es schrittweise anwächst/schrumpft ... laß mal dein Array in 3er-Schritten wachsen :zwinker:

Besser wäre da wohl etwas mit < und >, statt MOD.



@Der_Unwissende: klar ginge das ... is halt was schönes für Typen-Konvertierungs-Liebhaber.
Bei der eigenen Implementierung kann man dann allerdings noch zusätzliche Sachen mit einbauen, wenn man schon mal dabei ist ^^

negaH 24. Nov 2006 06:34

Re: Arrayoperationen beschleunigen
 
Delphi-Quellcode:
const
  PreAllocCount = (256 + 2) div 3;

var
  Count: Integer;
  MyArray: array of anytype;
begin
  Count := 0;
  while xyz do
  begin
    if Count mod (PreAllocCount * 3) = 0 then
      SetLength(MyArray, Count + (PreAllocCount * 3));
    MyArray[Count +0] := XYZ;
    MyArray[Count +1] := XYZ;
    MyArray[Count +2] := XYZ;
    Inc(Count, 3);
  end;
  SetLength(MyArray, Count);
end;

// Vermeidung der langsammen Division

var
  Count,Size: Integer;
  MyArray: array of anytype;
begin
  Count := 0;
  Size := 0;
  while xyz do
  begin
    if Size mod 256 = 0 then
      SetLength(MyArray, (Size + 256) * 3);
    Inc(Size);

    MyArray[Count +0] := XYZ;
    MyArray[Count +1] := XYZ;
    MyArray[Count +2] := XYZ;
    Inc(Count, 3);
  end;
  SetLength(MyArray, Count);
end;
Also sage nicht "es funktioniert nicht", es funktioniert doch wenn man ein bischen nachdenkt.

Der entscheidende Punkt auf den ich hinweisen möchte ist:

Ein Programmierer OHNE Backgroundwissen der Informatik, eben über Algorithmen, wird immer nur nach einer fertigen Lösung suchen können, mehr nicht. Es geht hier also nicht darum eine fertige Lösung zu präsentieren sondern das fehlende Grundwissen der Programmierung nachzuliefern.

Eine TList ist sehr oft überdimensioniert, unhandlich in der Benutzung aus Sicht der Typsicherheit (sprich TList mit Integern und Typcasts etc.pp.) und meistens langsammer als eine Lösung die nur 2 Zeilen mehr an Source benötigt weil der Programierer das fachspezifische Grundwissen intus hat bzw. beherrscht.

Was mich an Gausi's Vorschlägen so stört ist das es Programmiertechnische Tricks sind (also Mißbrauch der Array Strukturen und TypCast, Pointerarithmetiken). Natrülich nicht alle deine Vorschläge, dafür sind diese dann aus meiner Sicht schon wieder zu aufwendig und überdimensiert für die eigentliche Problemstellung

"Vermeidung von Reallokationen beim Anlegen und Füllen dynamischer Arrays"

und das ist diejenige Operation die meiner Meinung nach im praktischen Alltag am häufigsten zu einer besseren Performance führt.
Gruß Hagen

negaH 24. Nov 2006 06:50

Re: Arrayoperationen beschleunigen
 
Und da gäbe es ja noch Methode 7, bei der der Programmierer offensichtlich die meisten Informationen über seine Daten zur Hand hat

Delphi-Quellcode:

var
  MyArray: array of mytype;
  Count: Integer;
begin
  SetLength(MyArray, Anzhal der Daten XYZ);
  for (count := 0 to Anzhal der Daten XYZ -1 do
    MyArray[Count] := XYZ;
end;
Wir wissen also schon wieviele Daten auf uns zukommen, höchst wahrscheinlich deshalb weil der Programmierer systematisch seine "Umwelt" geplant hat und so das Gesamtproblem korrekt zerlegt hat in kleine Unterprobleme und auch die Effizienz dabei nicht aus den Augen gelassen hat.

Also statt "blind vorwärts irrend" und mit irgendwas ein Problem zu lösen, wird der Programmierer systematisch das Problem lösen indem er von Anfang an seine notwenige Umwelt (Sourcecode, Datentypen, Objekte, Algorithmen etc.pp) auswählt und kombiniert. Das kann er dann aber nur wenn er eine entsprechende "Wissensdatenbank" besitzt, also sein Handwerk beherrscht.

Gruß Hagen

DGL-luke 24. Nov 2006 07:20

Re: Arrayoperationen beschleunigen
 
Wobei ich aber doch den Hinweis fallen muss, dass der Programmierer manchmal vor Anfang der Schleife nicht weiß, wie viel auf ihn zukommt... Meine Methode ist da der ersten von negaH sehr ähnlich, aber ich lagere das meist in eine funktion aus:

Delphi-Quellcode:
var Arr: array of string;
    ArrOccupied: Integer;

function ArrayAdd(s: string)
begin
  Inc(ArrOccupied);

  //memory management
  if length(Arr) <= ArrOccupied then
    setlength(Arr, round(length(arr) * 1.72)+1);

  Arr[Arrocupied] := s;
  Result := ArrOccupied;
end;
ArrOccupied ist hierbei der Index des letzten belegten Elements. Diese 172% sind ein Erfahrnungswert, der öfters mal in Threads kursiert, weswegen ich ihn einfach ohne nachdenken benutze und nur zur sicherheit ein +1 anhänge (obwohls eigentlich gar nicht nötig ist :gruebel:, es sei denn length(array)=1)

negaH 24. Nov 2006 14:31

Re: Arrayoperationen beschleunigen
 
Hm, netter Wert -> 172%. Davon habe ich bisher noch nichts gehört.

Was mich aber leicht stören würde sind

1.) der explizite Aufruf einer Funktion
2.) die Fließkommaarithmetik
3.) der Aufruf von Length() bei jedem Einfügen
4.) globale Variable

denn das sind alles "Performance-bremsen" verglichen zu meiner direkten Methode. Im Grunde handelt es sich doch nur um ein Beispiel das man in den eigenen Sourcen direkt umsetzt. Dein Vorschlag ist schon wieder eine Generalisierung die auf Grund dessen einen zusätzlichen Overhead mitsichbringt.

Je nach Erfordernisse haben wir hier im Thread nun alle möglichen Wege aufgezeichnet, schön ;)

Gruß Hagen

DGL-luke 24. Nov 2006 14:53

Re: Arrayoperationen beschleunigen
 
1.) Neuere Delphi-Compiler sollten den inlinen
2.) ja. geht bestimmt auch per boolescher Verknüpfungen... aber das kann ich nicht^^
3.) Naja... man kann dafür auch eine zusätzliche variable deklarieren^^
4.) Wärs die lieber als typisierte private Konstante? ;) Kann man natürlich jederzeit innerhalb der am nchsten gelegenen Klasse deklarieren ;)

Das nur zder Vollständigkeit halber. :)

alzaimar 24. Nov 2006 15:07

Re: Arrayoperationen beschleunigen
 
Also das mit den 172% oder 176% oder was auch immer habe ich auch schon gehört, deckt sich aber nicht mit meinen Versuchen. Ich habe meine Arrays einfach immer von der Größe her verdoppelt. Das ist unterm Strich schneller als die 176% und auch nachvollziehbar: Es wird ja seltener vergrößert.

Kann mir jemand mathematisch beweisen, das die 172/176% optimal sind? Also ich meine, das es umso optimaler wird, je größer der Vergrößerungsfaktor ist. Nur praktikabel ist es nicht.

Der_Unwissende 24. Nov 2006 15:52

Re: Arrayoperationen beschleunigen
 
Zitat:

Zitat von alzaimar
Kann mir jemand mathematisch beweisen, das die 172/176% optimal sind? Also ich meine, das es umso optimaler wird, je größer der Vergrößerungsfaktor ist. Nur praktikabel ist es nicht.

Nicht dass das noch ansatzweise zum eigentlichen Topic gehört, aber optimal in Bezug auf was? Laufzeit oder Speicherausnuztung? Und für Letzteres wäre sicherlich mehr reservieren suboptimal. Aber ich glaube, dass keiner behauptet hatte, dass die 172/176% optimal sind, oder?

Aber mal interesse halber, mit welcher Größe startest du denn? Da hast du doch sicherlich auch einen Erfahrungswert, denke nicht dass du erst 1 Element hast und dann immer verdoppelst.

Gruß Der Unwissende

alzaimar 24. Nov 2006 16:09

Re: Arrayoperationen beschleunigen
 
Zitat:

Zitat von Der_Unwissende
Nicht dass das noch ansatzweise zum eigentlichen Topic gehört, aber optimal in Bezug auf was? Laufzeit oder Speicherausnuztung? Und für Letzteres wäre sicherlich mehr reservieren suboptimal. Aber ich glaube, dass keiner behauptet hatte, dass die 172/176% optimal sind, oder?

Aber mal interesse halber, mit welcher Größe startest du denn? Da hast du doch sicherlich auch einen Erfahrungswert, denke nicht dass du erst 1 Element hast und dann immer verdoppelst.

Doch, ich finde, das gehört zum Topic "Arrayoperationen beschleunigen". Und da es um "Beschleunigen" geht, ist logischerweise das "optimal" auf die Geschwindigkeit bezogen, insofern ist deine Frage überflüssig. Und es wird behauptet, die 172/176% seien irgendwie 'besser' als andere Faktoren, nicht unbedingt in diesem Thread, aber allgemein. Ich halte diese "magische Zahl" übrigens für einen Hoax, aber das nur am Rande.

Ich habe eine TStringDictionary , die arbeitet mit einer Hashmap, und die ist als ein Array implementiert. Wenn die Hashmap voll ist, muss ich das Array vergrößern. Ich habe mit 1.72 2/3, Fibbionacci etc. experimentiert und bin schlussendlich bei der 2 geblieben (als Vergrößerungsfaktor). 4 ist noch besser, aber so marginal, das mir da die 2 lieber ist.

Meine Anfangsgröße ist 997 (Primzahl, ist so bei Hashmaps), wobei es wirklich egal ist ob man mit 1 oder 997 anfängt. Jedenfalls bei meinen Versuchen, die 1-10 Millionen Strings in die Liste eingefügt haben.

Bis 2^31 Einträge in der Liste sind, wird diese bei einer Anfangsgröße von 997 Elementen 20x vergrößert. Ob ich beim Einfügen von 2^31 Elementen nun 30 (Anfangsgröße = 1) oder 20x vergrößere ist völlig egal: Das Laufzeitverhalten bleibt gleich, denn die 10 anfänglichen Vergrößerungen (Anfangsgröße=1, bis auf 1000 Elemente) geht einfach zu schnell und gehen in der Messung über die 1.000.000 Elemente unter.

Damit die StringDictionary auch für kleinere Mengen praktikabel ist, habe ich die Anfangsgröße doch auf 997 gesetzt. Damit kommen normale Anwendungen gänzlich ohne dynamische Vergrößerung aus.

Wenn ich dagegen mit kleineren Faktoren spiele, wird das Teil doch etwas langsamer. Also habe ich mich für 200% entschieden, was im Code auch irgendwie cooler aussieht, also (*1.72), obwohl das Geschmackssache ist.

Übrigens ist es entgegen meiner anfänglichen Meinung nicht so, das es umso schneller ist, je höher der Vergrößerungsfaktor ist. Ich hab mal die Kurve der zu Gesamtanzahl der zu verschiebenden Elemente ggü dem Vergrößerungsfaktor aufgezeichnet und das lokale Minimum liegt irgendwo bei 4-5 (sofern meine Formel stimmt).

Der_Unwissende 24. Nov 2006 18:30

Re: Arrayoperationen beschleunigen
 
Zitat:

Zitat von alzaimar
Doch, ich finde, das gehört zum Topic "Arrayoperationen beschleunigen". Und da es um "Beschleunigen" geht, ist logischerweise das "optimal" auf die Geschwindigkeit bezogen, insofern ist deine Frage überflüssig.

Entschuldige, war gerade geistig noch in einem anderen Thread, nehme alles zurück! :oops: Erst lesen, dann schreiben, da war doch was. Tut mir echt leid!

An die Messungen und die Hashmaps (gab doch einmal eine String und einmal eine Integer basierte?) kann ich mich (wieder ohne nochmal zu lesen) noch erinnern, die waren/sind echt gut/flink!

Ja, sorry nochmal, nichts für ungut! Hier in dem Thread gebe ich dir natürlich völlig recht!

Gruß Der Unwissende

alzaimar 24. Nov 2006 18:37

Re: Arrayoperationen beschleunigen
 
Ich hab mich schon gewundert, aber lass man, liegt am Wetter: Ich war dafür gestern dumm wie Brot.

himitsu 24. Nov 2006 18:37

Re: Arrayoperationen beschleunigen
 
Zitat:

Zitat von Der_Unwissende
An die Messungen und die Hashmaps (gab doch einmal eine String und einmal eine Integer basierte?) kann ich mich (wieder ohne nochmal zu lesen) noch erinnern, die waren/sind echt gut/flink!

Hier geht es mehr um das Array selber, wie man die Datenverarbeitung innerhalb des Arrays beschleunigt ist 'ne andere Sache.



[add]
klar sind die kurzen Inlineversionen schnell und schön ... verwende die kleinen Zwei-/Dreizeiler auch recht oft ... hab's da oben zwar schön in Funktionen verpackt (weil etwas übersichtlicher), aber nimand verbietet es einem, wenn man es direkt im Code verwendet (so wie z.B. bei 1.)

negaH 24. Nov 2006 20:08

Re: Arrayoperationen beschleunigen
 
Zitat:

1.) Neuere Delphi-Compiler sollten den inlinen
2.) ja. geht bestimmt auch per boolescher Verknüpfungen... aber das kann ich nicht^^
3.) Naja... man kann dafür auch eine zusätzliche variable deklarieren^^
4.) Wärs die lieber als typisierte private Konstante? Wink Kann man natürlich jederzeit innerhalb der am nchsten gelegenen Klasse deklarieren Wink
Hm, meine Antwort, einfach mal als Kontrapunkt betrachten

1.) davon weiß ich nichts und ich kenne keinen Compiler der einfach mal so aus überschwenglicher Eigenkreativität eine Funktion als Inline compiliert bei der der Programierer es nicht explizit vorgegeben hat. Viel eher ist meine Erfahrung, egal ob PASCAL/C Compiler, das Inline Funktionen bei weitem eben nicht das gleiche sind wie zb. Makros oder direkter Code. Viele Compiler machen da einen Unterschied wenn es um die Optimierung geht.

2.) Nein geht per Boolscher Verknüpfung eben nicht. Du multiplizierst mit einer Fließkommazahl und das kannst du nicht in Boolscher Algebra rechnen. Integer mod 256 = 0 geht degeben sehr wohl, da der Compiler das in Integer and $FF = 0 umsetzten kann.

3.) Und noch eine zusätzliche globale Variable, obwohl doch nur 3 zusätzliche Zeile im Sourcecode das Problem lokal lösen können.

4.) Hm, wieder ein Kniff obwohl die Lösung doch simpel ist

Ich meine das man die Logik beim Programmieren nicht so ansetzten sollte das man für alles eine fertige Klasse oder Bibliothek benötigt, schon garnicht für so wirklich simple Sachen. Manchesmal denke ich das viele Leute ein Problem versuchen viel komplizierter zu machen, ganz im Gegensatz zur Grundaufgabe eines Programmieres -> lösen von Problemen auf die einfachste Art.

Das soll jetzt keine Kritik an deiner Person oder deinem Vorschlag sein. Einfach nur so'n par Argumente die mir spontan in der Birne rumsausen ;)

@alzaimar:

Ähnliche Erfahrungen habe ich auch gemacht. Bisher habe ich noch nie eine Faustformel gefunden die auf alle Algorithmen und Problemstellungen und Datenaufkommen und underlaying Bibliotheksimplementierungen anwendbar ist. Die bisher beste durchschnittliche Vorgehensweise war die binäre Quadratische Annäherung, also die Verdopplung/Halbierung in unserem Fall. Am besten 2'er Potenzen. Das deckt sich in irgendeinerweise auch mit vielen anderen Verfahren wie "Binary Splitting-Divide & Conquer", "Binäre Suche", "QuickSort" etc.pp. Allerdings bin ich bei der Speicherallokation sehr sehr konservativ und alloziere lieber linear um einen Betrag +X. Am besten ist es aber wenn man schon von vornherein das Datenaufkommen kennt und dann gezielt reagieren kann. Und exakt das ist möglich wenn man im Gesamtkonzept seiner Programmierung darauf Einfluß nehmen kann. Die beste Optimierung findet also an diesem Punkt statt.

Man muß fairerweise aber auch sagen das wir hier über "Details" diskutieren, denn sehr oft sind es nicht solche Allozierungen wie diese hier im Forum die den Flaschenhals darstellen.

Gruß Hagen

himitsu 25. Nov 2006 13:29

Re: Arrayoperationen beschleunigen
 
Was das zuviele Length-Aufrufen angeht:

Bis auf die ersten beiden Varianten gibt's da wohl nicht mehr sooooviel Unterschied,
Delphi-Quellcode:
// if length(Arr) = 0 then
if Arr = nil then

// If Length(Arr) <> 0 Then
// If Length(Arr) > 0 Then
If Arr <> nil Then

// If Length(Arr) > 123 Then
If (Arr <> nil) and (PInteger(Integer(Arr) - 4)^ > 123) Then

// If Length(Arr) < 123 Then
If (Arr = nil) or (PInteger(Integer(Arr) - 4)^ < 123) Then

...
wenn man sich dagegen die Funktion ansieht ... abgesehen von dem zusetzlichen 2 Sprüngen (zur Funktion und zurück).

den nach Pascal übersetzt sieht die ja in etwa so aus:
Code:
Function Length(Arr): Integer;
  Begin
    If Arr = nil Then Result := 0
    Else Result := PInteger(Integer(Arr) - SizeOf(Integer))^;
  End;


PS an Borland: wie wäre es ohne die Funktion und direkt Inline (wie oben)? :zwinker:



Aber wer auf Kurz steht ... hier nochmal die Zwei-/Dreizeiler as InlineCode:
Code:
// entspricht 2.
[b]If[/b] [color=red]Arr[/color] <> nil [b]Then[/b] PInteger(Integer([color=red]Arr[/color]) - 4)^ := (PInteger(Integer([color=red]Arr[/color]) - 4)^ + [color=green]255[/color]) [b]and[/b] -[color=green]255[/color];
SetLength([color=red]Arr[/color], ([color=blue]NewSize[/color] + [color=green]255[/color]) [b]and[/b] -[color=green]255[/color]);
[b]If [color=red]Arr[/color] <> nil [b]Then[/b] PInteger(Integer([color=red]Arr[/color]) - 4)^ := [color=blue]NewSize[/color];


Code:
// ist zwar schneller/kürzer, aber es wird immer die Längen-Variable benötigt
SetLength([color=red]Arr[/color], ([color=blue]NewSize[/color] + [color=green]255[/color]) and -[color=green]255[/color]);
[color=red]ArrLen[/color] := [color=blue]NewSize[/color];

// und will man mal das Array ohne ArrLen weitergeben,
// sollte/muß die tatsächliche Länge nochmals angepaßt werden:
SetLength([color=red]Arr[/color], [color=red]ArrLen[/color]);


Dann sei nochmals darauf hingewiesen, daß "einige" eurer Codes das Array nur vergrößern
und speziell Hagen's Methoden mit MOD setzen voraus, daß immer ein bestimmter Punkt getroffen wird, bevor vergrößert/geändert wird.

Gut, bei mir ist es dagegen dann zwar nicht mehr ganz optimal, aber dafür kann/darf man dort auch mal in unterschiedlichen Schritten ändern und natürlich das Array auch wieder verkleinern.



Und ja, Methode 7 (siehe negaH) ist natürlich das Optimum, da dort nur einmal und genau auf das was nötig ist geändert wird.

alzaimar 27. Nov 2006 07:21

Re: Arrayoperationen beschleunigen
 
Hmitsu: Ich verstehe Dein bestreben, inline-Code zu erzeugen, aber wäre es nicht wirklich sinnvoller, die Array-Größe zu verdoppeln (oder zu vereinskommasiebenzweifachen :mrgreen: )? Dann ist es doch völlig egal, wie die SetLength-Routine arbeitet, nur bei der 'Length'-Funktion könnte man sich einen Funktionsaufruf sparen. Hier allerdings wäre es sicherlich noch einen Tick schneller, die aktuelle Größe des Arrays in einem Feld zu speichern... Wäre das nicht *noch* schneller?

himitsu 28. Nov 2006 12:33

Re: Arrayoperationen beschleunigen
 
Ich hab ja nichts dagegen, wenn man die aktuelle Größe in einer Extravariable speichert (siehe 1.),
nud kann das auch mal schnell unübersichtlich/unpraktisch werden.
z.B. bei vielen Arrays, oder wenn man das Array dann an andere (fremde) Funktionen übergeben möchte, denn da muß man dann entweder die zusätzliche Variable mitgeben, wenn das überhaupt geht).


Ansonsten mag verdoppeln, oder bei raschem anwachsen ein vermehrfachen recht schick,
aber bei "sehr" großen Arrays wohl auch nicht mehr gut (z.B. Speicherauslagerung durch Windows und massig ungenutzt reservierten Speicher).
Da ist dann wohl ein gut gewählter, fester Wert auch nicht zu verachten.



PS: auch wenn ich selber oftmals InlineCode verwende, waren die Inlines von mir nur wegen der "Funktions-Hasser" (nicht böse und ganz ernst gemeint).


Naja, daß die Standardfunktionen nicht so ganz optimal sind ist wohl klar und inzwischen sind hier wohl auch schon 'ne ganze Menge Möglichkeiten zusammengekommen, wie man da was verbessern könnte.
Und am Ende kommt es eh auf jeden Programmierer und das Programm drauf an, was wohl die bessere Lösung ist.


Und bei wenigen/seltenen Größenänderungen lohnt sich der "Aufwand" eh kaum.



Zitat:

Zitat von negaH
Man muß fairerweise aber auch sagen das wir hier über "Details" diskutieren, denn sehr oft sind es nicht solche Allozierungen wie diese hier im Forum die den Flaschenhals darstellen.

Na ja, ein Flaschenhals ist es dennoch.

Alleine mit sowas konnte ich z.B. in h-Sync die Verarbeitung von vielleicht 3 bis 4 Dateien die Sekunde auf knapp 1000 raufschrauben ... zum Ende hin, bei 'ner 7-stelligen Anzahl an Dateien.

Klar ist das nicht die einzige Engstelle, aber jede "kleine" vorteil verbessert das Gesamtergebnis.
Und vorallem dann, wenn es sich um soeine winzige Veränderung handelt, welche dennoch große Wirkungen zeigen kann.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:19 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz