C# / F# Performance comparison

Natural F# code (e.g. functional/immutable) is slower than natural (imperative/mutable object-oriented) C# code. However, this kind of F# is much shorter than usual C# code.
Obviously, there is a trade-off.

On the other hand, you can, in most cases, achieve performance of F# code equal to performance of C# code. This will usually require coding in imperative or mutable object-oriented style, profile and remove bottlenecks. You use that same tools that you would otherwise use in C#: e.g. .Net reflector and a profiler.

That having said, it pays to be aware of some high-productivity constructs in F# that decrease performance. In my experience I have seen the following cases:

  • references (vs. class instance variables), only in code executed billions of times

  • F# comparison (<=) vs. System.Collections.Generic.Comparer, for example in binary search or sort

  • tail calls — only in certain cases that cannot be optimized by the compiler or .Net runtime. As noted in the comments, depends on the .Net runtime.

  • F# sequences are twice slower than LINQ. This is due to references and the use of functions in F# library to implement translation of seq<_>. This is easily fixable, as you might replace the Seq module, by one with same signatures that uses Linq, PLinq or DryadLinq.

  • Tuples, F# tuple is a class sorted on the heap. In some case, e.g. a int*int tuple it might pay to use a struct.

  • Allocations, it’s worth remembering that a closure is a class, created with the new operator, which remembers the accessed variables. It might be worth to “lift” the closure out, or replaced it with a function that explicitly takes the accessed variables as arguments.

  • Try using inline to improve performance, especially for generic code.

My experience is to code in F# first and optimize only the parts that matter. In certain cases, it might be easier to write the slow functions in C# rather that to try to tweak F#. However, from programmer efficiency point of view makes sense to start/prototype in F# then profile, disassemble and optimize.

Bottom line is, your F# code might end-up slower than C# because of program design decisions, but ultimately efficiency can be obtained.

Leave a Comment