Ich habe eine seltsame Leistungseinbuße bekommen, die ich auf diesen Code reduziert habe:
%Vor% Der Unterschied zwischen add
und add1
ist der zusätzliche ()
am Ende.
Wenn ich es als x64 Release Build mit F # 3.1 auf .NET 4.5.1 erstelle, bekomme ich diese Ausgabe:
%Vor% Da der Typ von List<T>.Add
T -> unit
ist, würde ich erwarten, dass add
und add1
sich identisch verhalten sollten.
Mit ILdasm habe ich gefunden, dass add
kompiliert (einschließlich nur des relevanten Teils)
während add1
in
d. ohne den "Tail Call". Wenn ich die Tail Call Optimierung deaktiviere, laufen sowohl add
als auch add1
mit der gleichen Geschwindigkeit.
Warum bewirkt der Befehl tail.
, dass der Funktionsaufruf so viel langsamer ist? Ist das auch ein Fehler oder eine Funktion?
EDIT: Dies ist der ursprüngliche Code hier bemerkte ich dieses Verhalten. Wenn der Wert true
am Ende gelöscht wird, weist er den gleichen Leistungsabfall auf wie der obige Code.
Ich denke, ich habe herausgefunden, wo das Problem liegt und warum es mein Missverständnis ist, anstatt das Problem im F # Compiler oder .NET zu lösen.
Der Code
%Vor% bedeutet grob "call List<T>.Add
von der hinteren Aufrufposition auf dem Wert Vector3(j, j, j)
" während
bedeutet "Rufen Sie List<T>.Add
für den Wert Vector3(j, j, j)
auf und geben Sie dann unit
" zurück.
Typisch gibt es keinen Unterschied, da List<T>.Add
unit
zurückgibt, also nahm ich fälschlicherweise an, dass positions.Add
aufgerufen würde und dann add
den Wert unit
zurückgab, was der Rückgabewert von List<T>.Add
ist . Wie jedoch unter Ссылка angegeben , das JIT muss etwas "Stapelmagie" ausführen, wenn die Argumente der Schwanzfunktion nicht-trivial sind. Und hier kommt die Leistungslücke. Der Unterschied ist sehr subtil, aber es ist da.