2010-11-10 3 views
10

Ich versuche, das zu erhalten, was ich Messeinheitensystem nenne, indem ich double in struct umschließe. Ich habe C# -Strukturen wie Meter, Second, Degree usw. Meine ursprüngliche Idee war, dass nach dem Compiler inline alles, was ich hatte, eine Leistung die gleiche wie wenn Double verwendet würde.Verwenden von C# -Typen zum Ausdrücken von Maßeinheiten

Meine expliziten und impliziten Operatoren sind einfach und unkompliziert, und der Compiler führt sie tatsächlich inline, aber der Code mit Meter und Second ist 10 Mal langsamer als der gleiche Code mit Double.

Meine Frage ist: Warum kann C# -Compiler den Code mit Second nicht so optimal machen wie der Code mit Double, wenn er doch alles inline einfügt?

Zweitens wird wie folgt definiert:

struct Second 
{ 
    double _value; // no more fields. 

    public static Second operator + (Second left, Second right) 
    { 
     return left._value + right._value; 
    } 
    public static implicit Second operator (double value) 
    { 
     // This seems to be faster than having constructor :) 
     return new Second { _value = value }; 
    } 

    // plenty of similar operators 
} 

Update:

Ich habe nicht gefragt, ob struct hier passt. Es tut.

Ich habe nicht gefragt, ob der Code inline wird. JIT macht es inline.

Ich überprüfte Assembly-Operationen in der Laufzeit emittiert. Sie waren anders für Code wie folgt:

var x = new double(); 
for (var i = 0; i < 1000000; i++) 
{ 
    x = x + 2; 
    // Many other simple operator calls here 
} 

und wie folgt aus:

var x = new Second(); 
for (var i = 0; i < 1000000; i++) 
{ 
    x = x + 2; 
    // Many other simple operator calls here 
} 

gab es keine Anruf Anweisungen in der Demontage, so dass Operationen in der Tat inlined wurden. Der Unterschied ist jedoch signifikant. Leistungstests zeigen, dass die Verwendung von Second 10 Mal langsamer ist als die Verwendung von Double.

Also meine Fragen sind (Achtung!): Warum ist JIT generiert IA64-Code ist anders für die oben genannten Fälle? Was kann getan werden, um struct so schnell wie double zu machen? Es scheint keinen theoretischen Unterschied zwischen Doppel und Zweiter zu geben, was ist der tiefe Grund für den Unterschied, den ich gesehen habe?

+1

ist das ein "impliziter" oder "+" Operator? –

+0

Diese Frage könnte Sie interessieren: http://stackoverflow.com/questions/348853/units-of-measure-in-c-altimest – Benjol

+1

Ich weiß, dass Sie C# verwenden, aber haben Sie F # in Betracht gezogen? Es hat statische Einheiten eingebaut, die prüfen, was Sie suchen. Siehe http://stackoverflow.com/questions/40845/how-do-f-units-of-measure-work –

Antwort

1

Der C# Compiler nicht Inline nicht etwas - die JIT könnte das tun, ist aber nicht verpflichtet, zu. Es sollte immer noch viel schnell sein. Ich würde wahrscheinlich die implizite Konvertierung in den + entfernen aber (den Konstruktor Verwendung siehe unten) - ein weiterer Betreiber suchen durch:

private readonly double _value; 
public double Value { get { return _value; } } 
public Second(double value) { this._value = value; } 
public static Second operator +(Second left, Second right) { 
    return new Second(left._value + right._value); 
} 
public static implicit operator Second(double value) { 
    return new Second(value); 
} 

JIT inlining beschränkt sich auf bestimmte Szenarien. Wird dieser Code ihnen genügen? Schwer zu sagen - aber es sollte arbeiten und arbeiten schnell genug für die meisten Szenarien. Das Problem mit + ist, dass es einen IL-Opcode zum Hinzufügen von Doppel gibt; es tut fast keine Arbeit - wo-wie Ihr Code ein paar statische Methoden und einen Konstruktor aufruft; Es wird immer einige Overhead sein, auch wenn inline.

+0

Ich habe ein 'int' in eine Struktur (Implementierung von Festkomma) gehüllt und wenn der Jitter den Code inlinete (IMO sollte er aggressiver inline code), erzeugte er perfekten Assemblercode. Also wenn es inlined ist, gibt es wahrscheinlich überhaupt keinen Overhead. – CodesInChaos

4

Dies ist meiner Meinung nach, bitte schreiben Sie einen Kommentar, wenn Sie nicht einverstanden sind, anstatt still downvoting.

C# Compiler inline es nicht. JIT Compiler könnte, aber das ist indeterministisch für uns, weil JITer das Verhalten nicht einfach ist.

Im Fall von double werden tatsächlich keine Operatoren aufgerufen. Operanden werden direkt im Stapel mit dem Opcode add hinzugefügt. In Ihrem Fall wird die Methode op_Add aufgerufen plus drei struct Kopieren zu und von Stapel.

Um es zu optimieren, beginnen Sie mit dem Ersetzen struct durch class. Es wird zumindest die Anzahl der Kopien minimieren.

+2

... und Strukturen werden Sie auf dem Weg in Schwierigkeiten bringen. –

+0

Warum möchten Sie hier Klassen anstelle von Strukturen verwenden? Die Probleme mit seinem Beruf (die riesige Menge an Betreibern und Typen) werden sich nicht ändern, wenn er "Klasse" benutzt, aber die Leistung wird wahrscheinlich sehr fallen. – CodesInChaos

+0

@CodeInChaos ich benutze niemals 'struct'. Ich denke wirklich, dass es nur mit Interop verwendet werden sollte. "Leistung wird wahrscheinlich viel fallen" warum? erkläre bitte. – Andrey