Sprachen gesucht: Dynamische Compilierung (oder ein anderes Wort, dass ich nicht kenne)
-
loks schrieb:
Eine Möglichkeit wären da C# Expression Trees (C# 3.0)
"Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y.
You can compile and run code represented by expression trees. This enables dynamic modification of executable code, the execution of LINQ queries in various databases, and the creation of dynamic queries."
Leider ist da mit Sicherheit der Overhead größer als für ein paar simple
if
. Die Expression Trees werden ja intern auch über einen Polymorphiemechanismus gelöst.Ich kann mir nicht vorstellen, dass bei einfachen If-Abfragen hier ein messbarer Nachteil entsteht (es sei denn du misst wirklich jeden Takt - viel mehr braucht so ein
if
nicht). Ebenso wird der virtuelle Funktionsaufruf vernachlässigbar sein bei möglicherweise besserem Design.Noch etwas schneller ist vermutlich der Call über einen Funktionspointer - also einfach für jede Konfiguration eine eigene Funktion anlegen und einen Callpointer entsprechend umbiegen.
Crazy wäre, für jede Konfiguration ein eigenes Programm auszuliefern und über einen Launcher die richtige Variante zu starten. Gänzlich verrückt ist, in deinem Speicher rumzufuschen und die Funktion mit der gewünschten Variante zu überschreiben. Aber was war gleich die Steigerung der Steigerung von Premature Optimization?
-
SideWinder schrieb:
Ausgangssituation:
void this_is_called_very_very_often ()Kannst du "very very often" etwas quantifizieren?
Da es um Customizing geht, kann ich mir nicht so recht vorstellen, dass solche Funktionen wirklich so oft aufgerufen werden, dass sich die paar if-Abfragen in der Performance niederschlagen.
Also es wird sich nicht um Code handeln der in einer innersten, tief verschachtelte Schleife für Bildverarbeitung oder so ausgeführt wird. Oder?
-
ipsec schrieb:
Ich kann mir nicht vorstellen[...]
Noch etwas schneller ist vermutlich[...]Es ist selten gut seine (Software)Designentscheidungen auf Glauben zu basieren.
Der Gedanke hinter Expresseion Trees ist doch gerade, das man basierend auf der Configuration genau den Programmablauf zusammenbaut den man braucht, ganz ohne irgendwelche if's. Dieser Tree wird dann zu Laufzeit compiliert und kann ganz normal ausführt wie jede andere Methode.
-
loks schrieb:
ipsec schrieb:
Ich kann mir nicht vorstellen[...]
Noch etwas schneller ist vermutlich[...]Es ist selten gut seine (Software)Designentscheidungen auf Glauben zu basieren.
Der Gedanke hinter Expresseion Trees ist doch gerade, das man basierend auf der Configuration genau den Programmablauf zusammenbaut den man braucht, ganz ohne irgendwelche if's. Dieser Tree wird dann zu Laufzeit compiliert und kann ganz normal ausführt wie jede andere Methode.
Schön wie du Wortfetzen aus dem Zusammenhang reißt. Ich kenne weder sein genaues Problem noch die Umstände noch z.B. den Anteil der kritischen Ifs an der gesamten Funktion. Natürlich kann ich nur vermuten. Und messen muss man am Ende in jedem Fall.
Und kompiliert oder nicht haben die Expression Trees einen Overhead. Auf jeden Fall is das Invoken eines Delegates in C# höchstens gleich schnell wie das Callen einer Funktion über einen Funktionspointer in C++. Da Delegates immer noch einen this-Zeiger haben entspricht deren Aufruf wohl etwa (ich sage wohl etwa, weil ich es gerade nicht nachgemessen habe) einen Funktionszeigeraufruf plus Aufruf einer virtuellen Funktion. In C++ kann man also für jede Konfiguration eine Funktion bauen (mit Templates ganz automatisch) und nimmt einen Funktionspointer oder man macht es über virtuelle Funktionen.
Ganz davon abgesehen wird aber, wenn es wie in SideWinders Fall bei der Performance auf jeden Takt ankommt, C# sowieso nicht zur Debatte stehen.
-
Ich befürchte ich habe zwei Fragen von mir vermischt, nun da ich darüber nachdenke ist es peinlich.
Frage 1: Wie löst ihr:
void is_called_10000_times_per_second () { if (cond) doA(); else doB(); }
Am schönsten wäre ja ein:
void is_called_10000_times_per_second () { if (cond [MY_LABEL]) doA(); else doB(); } void reload_config () { ... revalidate(MY_LABEL); }
Das untersützt aber keine Sprache (weil auch kein Prozessor?). Damit der Prozessor nicht erst wieder jedes Mal nachsehen muss ob MY_LABEL invalidiert worden ist, kann ich aktiv sagen "jetzt revalidieren". Da es diese Lösung aber ohnehin nicht gibt: Wie geht ihr hier vor? Ignoriert ihr soetwas? Funktionspointer sind nicht ausreichend, da sich mehrere ifs in der Funktionalität verschachteln könnten, teilweise ausgeführter Code ganz wegfällt (dann will ich auch keinen leeren FunCall, etc.)
Frage 2: Ein Software-Architektur-Problem im Bereich Customizing. Hier ist Performance eigentlich nicht wichtig und ich will das oben beschriebene Customizing-Problem lösen. Denkt ihr bin ich mit "Mixins" am richtigen Weg? Was haltet ihr von Mixins? Welche Sprachen unterstützen Mixins bzw. lassen sie zumindest über Umwege realisieren? Gibt es andere Lösungen? Was ist der gängige Weg?
MfG SideWinder
-
SideWinder schrieb:
Frage 1: Wie löst ihr:
void is_called_10000_times_per_second () { if (cond) doA(); else doB(); }
Very very often ist 10000-mal pro Sekunde? Wenn der Wahrheitswert von cond über längere Zeit gleich bleibt, sehe ich hier überhaupt kein Problem.
-
Das war mehr eine ausgedachte Zahl denn eine fixe Sache. Stell' dir die Zahl skalierbar vor. Ist es immer noch egal wenn wir von 1 Mio sprechen? Von 1 Mrd? (Edit: Soll ja auch in Zukunft noch Spaß machen, vor 20 Jahren waren vielleicht auch die 10000 Aufrufe viel)
MfG SideWinder
-
In C++ kann natürlich statt
void is_called_10000_times_per_second () { if (cond) doA(); else doB(); }
auch generell darüber nachdenken, zwei verschiedene Methoden zu implementieren
void is_called_10000_times_per_second_A() { doA(); } void is_called_10000_times_per_second_B() { doB(); }
und den Aufruf von außen per template oder per Funktionspointer zu steuern. In diesem Fall kann bei einer "Neu-Konfiguration" der Funktionspointer ausgetauscht oder eine Klasse mit einem anderen template parameter instanziiert werden.
-
Das ist vielleicht in so einfachen Fällen möglich, aber was tun falls:
// bisheriger code ... ... if () { ... if() { } } ...
Und dann wünscht sich einer von 20 Kunden im inneren if noch eine zusätzliche Ausgabe. Wie vorgehen?
... ... if () { ... if() { if(kunde == KUNDE3) print(); } }
a) Ich muss den aktuellen Kunden überallhin durchreichen
b) Ich bekomme mit der Zeit einen Fleckenteppich
c) Falls ich es zur compile-time unterscheide, muss ich verschiedene Releases warten
d) Falls ich deinen FuncPointer-Ansatz wähle, habe ich das Problem, dass ich statt if(kunde == KUNDE3) print(); irgendetwas wie possible_additional_print() aufrufen muss, ein FuncPtr der bei non-KUNDE3-LEuten in einen leeren Funktionscall mündet?Klingt nicht allzu schön. Ich könnte mir vorstellen:
a) Ich kann von anderer Stelle auf den Syntax-Tree zugreifen und an eine bestimmte Stelle die Ausgabe einfügen.
b) Damit ich auch weiß, dass es das gibt werden solcherlei Additionen irgendwo annotiert/festgehalten, so dass die IDE dies als Information in der Zeile anzeigt (ui das wäre fein).MfG SideWinder
-
SideWinder schrieb:
Eine Idee die mir eingefallen ist, ist die Klasse selbst zu Programmstart bzw. nach einem "Reload from Config" dynamisch zu erweitern. Welche Sprachen unterstützen das?
Die Antwort wird dir evtl nicht gefallen
http://de.wikipedia.org/wiki/Smalltalk-80_(Programmiersprache)
mit der message compile: kann man den Klassen zur Laufzeit neue Methoden verpassen.
ps.
Sprachen mit mixins gibt's wie Sand am Meer, such dir eine aus
-
Ja, Mixins sind schon ein sehr guter Ansatz. Ich weiß nur nicht...ist das eine gute Lösung? Hat jemand schon in großem Stil Mixins verwendet?
MfG SideWinder