![]() |
Delphi-Version: XE2
Anonymous Methods/Operationen auf Array
Hallo liebe Leute!
Ich suche derzeit, ohne besonderem Hintergrund, einen möglichst generischen Weg um eine Operation möglichst schnell auf einem gesamten Array auszuführen. Mit Anonymen Methoden lässt sich das ja relativ einfach realisieren:
Delphi-Quellcode:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type TProc = reference to Function(aValue: Integer): Integer; const count = 10000000; // 10 Millionen type TForm1 = class(TForm) procedure FormClick(Sender: TObject); private arr: array [0 .. count - 1] of Integer; Procedure ForEachMul(const aFactor: Integer); Procedure ForEach(const aProc: TProc); procedure Output(const TimeNormal, TimeAnon: double); Procedure Test; { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.ForEach(const aProc: TProc); var I: Integer; begin for I := 0 to count - 1 do begin Self.arr[I] := aProc(arr[I]); end; end; procedure TForm1.ForEachMul(const aFactor: Integer); var I: Integer; begin for I := 0 to count - 1 do begin Self.arr[I] := Self.arr[I] * aFactor; end; end; procedure TForm1.FormClick(Sender: TObject); begin Test; end; procedure TForm1.Output(const TimeNormal, TimeAnon: double); begin Self.Canvas.TextOut(10, 10, 'Zeit normal: ' + TimeNormal.ToString()); Self.Canvas.TextOut(10, 15 + Self.Canvas.TextHeight('Text'), 'Zeit anon: ' + TimeAnon.ToString()); end; procedure TForm1.Test; var t1, t2, t3, f: Int64; begin QueryPerformanceFrequency(f); QueryPerformanceCounter(t1); Self.ForEachMul(2); QueryPerformanceCounter(t2); Self.ForEach( Function(aValue: Integer): Integer begin result := aValue * 2; end); QueryPerformanceCounter(t3); Self.Output((t2 - t1) / f, (t3 - t2) / f); end; end. Leider scheint es ein Grundgesetz zu sein, dass Flexibilität und Geschwindigkeit umgekehrt proportional zusammenhängen :( Mit der Anonymen Methode ist halt das Problem, dass bei jedem Aufruf eine Referenz aufgelöst werden muss und auch sonst noch einiges an Verwaltungsaufwand betrieben werden wird. Vermutlich daher benötigt diese Version auch fast die doppelte Zeit der normalen Methode (auf meinem Rechner). Gibt es schnellere Methoden, ohne Flexibilität aufgeben zu müssen? Ich bin über jede Idee, der ich nachgehen kann, sehr dankbar! nachgepatcht: Ich weiß natürlich, dass ich das auch mit Pointern auf Prozeduren und ähnlichen Konstrukten erreichen kann. Das würde wahrscheinlich sogar ein kleines Etwas an Geschwindigkeit bringen. Aber eines der Hauptprobleme bleibt: Es ist vom Prozessor (und ein paar anderen Dingen) abhängig, ob ich dann bei der Verarbeitung eines jeden Arrays ein Cache-Miss bekomme, weil der Programmcounter dauernd herumspringt. Selbst wenn der L1-Cache als Set-Associative-Cache ausgeführt ist, sollte das zu Geschwindigkeitseinbußen führen. Mein Traum wäre insofern natürlich, wenn ich irgendwie von außen in die ForEach-Methode einen Code einpflanzen könnte (statt der Multiplikation im Code oben, der dann innerhalb dieser Methode ausgeführt wird. Der Code kann dort zur Laufzeit auch gerne statisch bleiben. Im Prinzip würde es mir darum gehen, verschiedene Operationen, die ich auf Arrays anwenden möchte, an einer anderen Stelle (Unit, Klasse, etc...) semantisch zusammen zu fassen (z.B. Physik.Kinematik...). |
AW: Anonymous Methods/Operationen auf Array
Imho nein. Außer vielleicht Assembler.
Es ist schon meistens so, das Flexibilität (insbesondere saubere Architektur und Code) nicht mit Performance einhergeht, zumindest was die letzten 10% anbelangt. Hier ist das sogar extremer, aber es ist logisch, denn der Unterschied zwischen 'a[i] := a[i]*2' und einer anonymen Methode mit Parameter, Rückgabewert, Aufruf und Rücksprung' ist schon gewaltig. Was Du allerdings machen könntest, wäre eine 'kompilierende Scriptengine' zu nehmen, die Dir den Code kompiliert, d.h. Du hast deine Funktionen als Quellcode vorrätig (bzw. den Rumpf) und baust Dir dann eine Funktion zusammen, à la: (Hier ist das Template)
Delphi-Quellcode:
In deiner Bibliothek von Manipulationen steht dann z.B.
Procedure $Name$ (var a : TMyArray);
var i : Integer; $localVariables$ begin $Initialize$ for i:= low(a) to High(a) do begin $CodeToInject$ end end;
Code:
oder
Name=MultiplyBy2
localVariables= Initialize= CodeToInject=a[i] := a[i]*2
Code:
Du ersetzt also die Platzhalter ('$blabla$') durch die konkreten Codeschnipsel.
Name=Fibionacci
localVariables= f : integer; Initialize= f:= 0; CodeToInject= a[i] := a[i]+f; f:=a[i]; Beispiel:
Delphi-Quellcode:
Als 'kompilierende Scriptengine' kannst Du FPC nehmen, d.h. Du erzeugst einfach aus dem o.g. Code eine DLL, bindest die dynamisch ein, und rufst die Methode auf. Dann ist das genauso schnell wie Delphi selbst.
Procedure Fibionacci (var a : TMyArray);
var i : Integer; f : integer; begin f:= 0; for i:= low(a) to High(a) do begin a[i] := a[i]+f; f:=a[i]; end end; |
AW: Anonymous Methods/Operationen auf Array
Danke für die Antwort!
Ich habs befürchtet, dass es einfach nicht geht. Ist ja auch irgendwie logisch. Die Indirektion bekommt man einfach nicht weg, wenn man Flexibilität braucht. Ich werde mir Deine Idee mal genauer anschauen! Es ist wieder ein neues Gebiet zum einlernen. Da findet sich ja einiges positives daran! Letztlich hatte ich nur die Hoffnung, dass sich vielleicht eine Lösung zur Compile-Time finden lassen würde. Die Idee wäre der Deinigen im Prinzip nicht unähnlich: Während der Entwicklung lässt man einen Platzhalter für die Operation in der For-Each-Methode und programmiert einfach wie bisher mit der Anonymen Methode. Beim Compilieren könnte dann der Code der Anonymen Methode in der For-Each-Methode eingefügt werden. Für jeden Aufruf der For-Each-Methode mit unterschiedlichen Anonymen Methoden wird eine neue Methode erzeugt. Aber soetwas wirds vermutlich auch nicht spielen. |
AW: Anonymous Methods/Operationen auf Array
Nimm VC++, der inlined anonyme Methoden :P
|
AW: Anonymous Methods/Operationen auf Array
Das wäre ja wirklich ziemlich genau das, was ich (ver)suche...
Wäre es eigentlich möglich ein Plugin für Delphi zu schreiben, mit zur Compile-Time Code irgendwo eingefügt werden könnte? Ich hab leider nicht die geringste Ahnung, von Plugins in Delphi! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:59 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 by Thomas Breitkreuz