Natürlicher F#-Code (z. B. funktional/unveränderlich) ist langsamer als natürlicher (imperativer/veränderlicher objektorientierter) C#-Code. Allerdings ist diese Art von F#-Code viel kürzer als gewöhnlicher C#-Code. Offensichtlich gibt es einen Kompromiss.
Andererseits können Sie in den meisten Fällen mit F#-Code die gleiche Leistung erreichen wie mit C#-Code. Dazu ist es in der Regel erforderlich, im imperativen oder veränderlichen objektorientierten Stil zu kodieren, Profile zu erstellen und Engpässe zu beseitigen. Sie verwenden dieselben Tools, die Sie auch in C# verwenden würden: z. B. den .Net-Reflektor und einen Profiler.
Dennoch lohnt es sich, sich einiger hochproduktiver Konstrukte in F# bewusst zu sein, die die Leistung verringern. Nach meiner Erfahrung habe ich die folgenden Fälle gesehen:
-
Referenzen (im Gegensatz zu Klasseninstanzvariablen), nur in milliardenfach ausgeführtem Code
-
F#-Vergleich (<=) vs. System.Collections.Generic.Comparer, z.B. bei binärer Suche oder Sortierung
-
Tail-Aufrufe - nur in bestimmten Fällen, die nicht durch den Compiler oder die .Net-Laufzeit optimiert werden können. Wie in den Kommentaren erwähnt, hängt dies von der .Net-Laufzeitumgebung ab.
-
F#-Sequenzen sind doppelt so langsam wie LINQ. Dies ist auf Referenzen und die Verwendung von Funktionen in der F#-Bibliothek zurückzuführen, um die Übersetzung von seq<_> zu implementieren. Dies ist leicht zu beheben, da Sie das Seq-Modul durch ein Modul mit denselben Signaturen ersetzen können, das Linq, PLinq oder DryadLinq verwendet.
-
Tupel, F# Tupel ist eine auf dem Heap sortierte Klasse. In manchen Fällen, z.B. bei einem int*int Tupel, kann es sich lohnen, ein struct zu verwenden.
-
Allokationen ist zu bedenken, dass eine Closure eine Klasse ist, die mit dem new-Operator erstellt wird und sich die zugegriffenen Variablen merkt. Es könnte sich lohnen, die Closure herauszunehmen oder sie durch eine Funktion zu ersetzen, die die Variablen, auf die zugegriffen wird, explizit als Argumente aufnimmt.
-
Versuchen Sie, Inline zu verwenden, um die Leistung zu verbessern, insbesondere bei generischem Code.
Meiner Erfahrung nach sollte man zuerst in F# programmieren und nur die wichtigen Teile optimieren. In bestimmten Fällen kann es einfacher sein, die langsamen Funktionen in C# zu schreiben, als zu versuchen, F# zu optimieren. Aus der Sicht der Programmierereffizienz ist es jedoch sinnvoll, mit dem Prototyping in F# zu beginnen und dann das Profil zu erstellen, zu zerlegen und zu optimieren.
Unterm Strich könnte Ihr F#-Code aufgrund von Programmdesign-Entscheidungen langsamer sein als C#, aber letztendlich kann Effizienz erreicht werden.